iv-3d-lib
Version:
A reusable ThreeJS library providing features for Ivee 3D Editor.
2,455 lines • 86.2 kB
text/typescript
import * as THREE from 'three';
import * as dat from 'dat-gui';
import { Stats } from './stats';
import * as cfg from './wgl-util-cfgs';
import OrbitControls = require('three-orbitcontrols');
// import OrbitControls from 'three-orbitcontrols';
import TrackballControls = require('three-trackballcontrols');
// import TrackballControls from 'three-trackballcontrols';
import * as leapControls from 'threeleapcontrols';
import StereoEffect = require('three-stereoeffect');
import AnaglyphEffect = require('three-anaglypheffect');
import AsciiEffect = require('three-asciieffect');
import * as css3d from 'three-css3drenderer';
import { WglUtilContentChangedArgs, ContentChangedType } from './wgl-util-content-changed-args';
import { OBJLoader } from 'three/examples/js/loaders/OBJLoader.js';
export class WglUtil {
public cfg: cfg.WglUtilCfg;
public glScene: THREE.Scene;
public camera: THREE.Camera;
public cameraHelper: THREE.CameraHelper;
public glRenderer: THREE.WebGLRenderer;
public raycaster: THREE.Raycaster;
public orbitControls: OrbitControls;
public trackballControls: TrackballControls;
public leapCameraControls: leapControls.LeapCameraControls;
public leapObjectsControls: leapControls.LeapObjectControls[] = [];
public axis: THREE.AxisHelper;
public axisArrowX: THREE.ArrowHelper;
public axisArrowY: THREE.ArrowHelper;
public axisArrowZ: THREE.ArrowHelper;
public stats: Stats;
public dndSelectedObject: THREE.Object3D;
public dndIntersectedObject: THREE.Object3D;
public dndSelectedObjectBoxHelper: THREE.BoxHelper;
public datGui: dat.GUI;
public guiControls;
public objects: any[] = [];
public parent: any = null;
public grid: THREE.GridHelper;
// public projector: THREE.Projector;
public stereoEffect: StereoEffect;
public mirrorCubeCamera: THREE.CubeCamera;
public mirrorCube = new THREE.Mesh;
public cssScene: THREE.Scene;
public cssRenderer: css3d.CSS3DRenderer;
private contentChanged: CustomEvent;
constructor() {
console.log(OBJLoader);
this.cfg = <cfg.WglUtilCfg>{
useAxis: true,
useOrbit: true,
useTrackball: false,
useStats: true,
useDatGui: true,
statsId: 'stats',
canvasId: 'canvas',
useAsciiEffect: false,
useAnaglyphEffect: false,
anaglyphFocalLength: 125,
useGridHelper: false,
useStereoEffect: false,
useCssRender: false
};
this.glScene = null;
this.camera = null;
this.glRenderer = null;
this.raycaster = null;
this.orbitControls = null;
this.trackballControls = null;
this.axis = null;
this.stats = null;
this.dndSelectedObject = null;
this.dndIntersectedObject = null;
this.dndSelectedObjectBoxHelper = null;
}
private asciiEffect: AsciiEffect;
private anaglyphEffect: AnaglyphEffect;
public cameraCfg: cfg.CameraCfg = <cfg.CameraCfg>{
fov: 50, aspect: window.innerWidth / window.innerHeight, near: 0.1, far: 10000,
position: { x: 200, y: 200, z: 200 }
}
public rendererCfg: cfg.RendererCfg = <cfg.RendererCfg>{
color: 0xFF0000, alpha: 0.5, width: window.innerWidth, height: window.innerHeight, shadowMapEnabled: true, antialias: true,
useCanvas: false
}
public sceneCfg: cfg.SceneCfg = <cfg.SceneCfg>{
useFog: true, fogColor: 0xffffff, fogMistDensity: 0.015, showAxis: true, axisSize: 20, useAxisArrows: true, axisArrowHeadLength: 2,
showGrid: true, gridSize: 10, gridDivisions: 10, gridColorCenterLine: 0x444444, gridColor: 0x888888
}
public orbitCfg: cfg.OrbitCfg = <cfg.OrbitCfg>{
minDistance: -10000, maxDistance: 10000
}
public trackballCfg: cfg.TrackballCfg = <cfg.TrackballCfg>{
rotateSpeed: 1.0,
zoomSpeed: 1.2,
panSpeed: 0.8,
noZoom: false,
noPan: false,
staticMoving: true,
dynamicDampingFactor: 0.3
}
public lightCfg: cfg.LightCfg = <cfg.LightCfg>{
color: 0x0c0c0c, intensity: 0xffffff
}
public dirLightCfg: cfg.DirLightCfg = <cfg.DirLightCfg>{
color: 0xFFFFFF, intensity: 1.5, position: { x: 40, y: 60, z: -10 }, shadowCameraFov: 70, castShadow: true, showHelper: true, showHelperRuntime: false, size: 5
}
public pointLightCfg: cfg.PointLightCfg = <cfg.PointLightCfg>{
color: 0x00FF00, intensity: 3, distance: 150, position: { x: 70, y: 5, z: 70 }, helperSphereSize: 3, showHelper: true, showHelperRuntime: false
}
public hemisphereLightCfg: cfg.HempisphereLightCfg = <cfg.HempisphereLightCfg>{
skyColor: 0xFFFFFF, groundColor: 0xFFFFFF, intensity: 1, position: { x: 40, y: 60, z: -10 }, showHelper: true, showHelperRuntime: false
}
public spotLightCfg: cfg.SpotLightCfg = <cfg.SpotLightCfg>{
color: 0xFFFFFF, intensity: 3, distance: 150, position: { x: 70, y: 5, z: 70 }, showHelper: true, showHelperRuntime: false, angle: Math.PI / 2, penumbra: 0, decay: 0
}
public lineCfg: cfg.LineCfg = <cfg.LineCfg>{
start: { x: 0, y: 0, z: 0 }, end: { x: 10, y: 10, z: 10 }, color: Math.random() * 0xFFFFFF
}
public planeCfg: cfg.PlaneCfg = <cfg.PlaneCfg>{
width: 60, height: 20, widthSegments: 1, heightSegments: 1, color: Math.random() * 0xFFFFFF, position: { x: 0, y: 0, z: 0 },
receiveShadow: true
}
public circleCfg: cfg.CircleCfg = <cfg.CircleCfg>{
radius: 4, segments: 20, thetaStart: 0, thetaLength: 2 * Math.PI, color: Math.random() * 0xFFFFFF, wireframe: false, position: { x: 20, y: 4, z: 2 },
castShadow: true, rotation: { x: 0, y: 0, z: 0 }
}
public cubeCfg: cfg.CubeCfg = <cfg.CubeCfg>{
width: 4, height: 4, depth: 4, color: Math.random() * 0xFF0000, wireframe: false, position: { x: -4, y: 3, z: 0 },
widthSegments: 1, heightSegments: 1, depthSegments: 1,
castShadow: true, rotation: { x: 0, y: 0, z: 0 }, rotationSpeed: 0.5
}
public sphereCfg: cfg.SphereCfg = <cfg.SphereCfg>{
radius: 4, widthSegments: 20, heightSegments: 20, phiStart: 0, phiLength: 2 * Math.PI, thetaStart: 0, thetaLength: 2 * Math.PI,
color: Math.random() * 0xFF0000, wireframe: false, position: { x: 20, y: 4, z: 2 },
castShadow: true, rotation: { x: 0, y: 0, z: 0 }
}
public cylinderCfg: cfg.CylinderCfg = <cfg.CylinderCfg>{
radiusTop: 20, radiusBottom: 20, height: 100, radiusSegments: 8, heightSegments: 1, openEnded: false, thetaStart: 0, thetaLength: 2 * Math.PI, color: Math.random() * 0xFFFFFF,
position: { x: 0, y: 0, z: 0 }
}
public torusCfg: cfg.TorusCfg = <cfg.TorusCfg>{
radius: 8, tube: 4, radialSegments: 8, tubularSegments: 6, arc: 2 * Math.PI
}
public torusKnotCfg: cfg.TorusKnotCfg = <cfg.TorusKnotCfg>{
radius: 8, tube: 4, radialSegments: 8, tubularSegments: 6, p: 2, q: 3
}
public pointsCfg: cfg.PointsCfg = <cfg.PointsCfg>{
color: Math.random() * 0xFFFFFF, radius: 0.2, transparent: true, offset: { x: -15, y: -15, z: -15 }, step: { x: 30, y: 30, z: 30 }
}
public pointsFromGeomCfg: cfg.PointsFromGeomCfg = <cfg.PointsFromGeomCfg>{
color: 0x000000, size: 0.1, scale: 1
}
public particleCfg: cfg.ParticleCfg = <cfg.ParticleCfg>{
count: 100, size: 1, range: 500, transparent: true, opacity: 0.5, vertexColors: [], sizeAttenuation: true, color: 0xFF0000
}
public textureCfg: cfg.TextureCfg = <cfg.TextureCfg>{
srcDir: 'assets/textures/', position: { x: 0, y: 0, z: 0 }, width: 100, height: 100, autoplay: true, loop: true, video: null, texture: null,
canvas: <cfg.CanvasCfg>{ width: 200, height: 50, font: '24px Arial', text: '', textColor: '#000', backgroundColor: '#fff' }
}
public shadersCfg: cfg.ShadersCfg = <cfg.ShadersCfg>{
vertexShaderId: 'vertexShader', fragmentShaderId: 'fragmentShader', uniforms: {}, attributes: {}, srcDir: 'assets/shaders/glsl/'
}
public skyBoxCfg: cfg.SkyBoxCfg = <cfg.SkyBoxCfg>{
srcFile: 'assets/textures/skyboxsun25degtest.png', srcDir: 'assets/textures/sky1/', px: 'px.jpg', py: 'py.jpg', pz: 'pz.jpg', nx: 'nx.jpg', ny: 'ny.jpg', nz: 'nz.jpg', size: 1024,
width: 5000, height: 5000, depth: 5000
}
public objModelCfg: cfg.ObjModelCfg = <cfg.ObjModelCfg>{
srcDir: 'assets/models/'
}
public textCfg: cfg.TextCfg = <cfg.TextCfg>{
text: '',
height: 10, size: 50, hover: 30, curveSegments: 4, bevelEnabled: true, bevelThickness: 2, bevelSize: 1.5, bevelSegments: 3,
font: 'optimer', // helvetiker, optimer, gentilis, droid sans, droid serif
weight: 'bold', // normal bold
style: 'normal', // normal italic
material: 0, extrudeMaterial: 1,
useMirror: false,
textMaterial: null,
textMesh: null, textMeshMirror: null,
offsetX: 0,
frontColor: null,
sideColor: null
}
/*
public gridHelperCfg: cfg.GridHelperCfg = <cfg.GridHelperCfg>{
size: 10,
divisions: 10,
colorCenterLine: 0x444444,
colorGrid: 0x888888
}
*/
public matCfg = {
color: 0x000000, wireframe: false
}
public spriteCfg: cfg.SpriteCfg = <cfg.SpriteCfg> {
map: null, color: 0x000000
}
public mirrorCubeCfg: cfg.MirrorCubeCfg = <cfg.MirrorCubeCfg>{
near: 0.1, far: 10000, resolution: 1024,
dimension: <cfg.XYZ>{ x: 4, y: 4, z: 1 },
position: <cfg.XYZ>{ x: 100, y: 100, z: 100 }
};
private mousePosition: THREE.Vector3 = new THREE.Vector2();
private dndPlane: THREE.Plane = new THREE.Plane();
private dndOffset: THREE.Vector3 = new THREE.Vector3();
private dndIntersection: THREE.Vector3 = new THREE.Vector3();
public copyCfg(srcCfg, destCfg) {
for(let p in srcCfg) {
if(destCfg.hasOwnProperty(p)) {
destCfg[p] = srcCfg[p];
}
}
}
Android = () => {
return navigator.userAgent.match(/Android/i);
}
BlackBerry = () => {
return navigator.userAgent.match(/BlackBerry/i);
}
iOS = () => {
return navigator.userAgent.match(/iPhone|iPad|iPod/i);
}
Opera = () => {
return navigator.userAgent.match(/Opera Mini/i);
}
Windows = () => {
return navigator.userAgent.match(/IEMobile/i);
}
public isMobile(): any {
return {
Android: this.Android(),
Blackberry: this.BlackBerry(),
iOS: this.iOS(),
Opera: this.Opera(),
Windows: this.Windows(),
any: () => {
return (this.Android() || this.BlackBerry() || this.iOS() || this.Opera() || this.Windows());
}
};
}
public static detectWebGL(): boolean {
try {
let canvas = document.createElement('canvas');
return !!(window['WebGLRenderingContext'] && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));
}
catch (e) {
console.log('WglUtil.detectWebGL: ', e);
return false;
}
}
setOptions (cfg) {
if(cfg) {
this.copyCfg(cfg, this.cfg);
}
}
setOption (name: string, value: any) {
if(this.cfg.hasOwnProperty(name)) {
this.cfg[name] = value;
}
}
getUrl(url, onSuccess?, onError?) {
var request = new XMLHttpRequest();
request.open('GET', url, true);
request.onload = () => {
if (request.status >= 200 && request.status < 400) {
// Success!
// var data = JSON.parse(request.responseText);
let data = request.responseText;
if (onSuccess) {
onSuccess(data);
}
} else {
let errMsg = 'Error returned from server';
console.error(errMsg, request);
if (onError) {
onError(new Error(errMsg));
}
}
};
request.onerror = (err) => {
console.error('Error returned from server', err);
if (onError) {
onError(err);
}
};
request.send();
}
init (sceneConfig?: cfg.SceneCfg, cameraConfig?: cfg.CameraCfg, rendererConfig?: cfg.RendererCfg, orbitCfg?: cfg.OrbitCfg, trackballCfg?: cfg.TrackballCfg) {
if(sceneConfig) {
this.copyCfg(sceneConfig, this.sceneCfg);
}
if(cameraConfig) {
this.copyCfg(cameraConfig, this.cameraCfg);
}
if(rendererConfig) {
this.copyCfg(rendererConfig, this.rendererCfg);
}
THREE.ImageUtils.crossOrigin = '';
this.glScene = new THREE.Scene();
if(this.rendererCfg.useCanvas) {
this.glRenderer = null; // new THREE.CanvasRenderer();
}
else {
this.glRenderer = new THREE.WebGLRenderer({ alpha: true, antialias: this.rendererCfg.antialias });
}
this.glRenderer.setClearColor(this.rendererCfg.color, this.rendererCfg.alpha);
this.glRenderer.setSize(this.rendererCfg.width ? this.rendererCfg.width : window.innerWidth, this.rendererCfg.height ? this.rendererCfg.height : window.innerHeight); //renderer.width, renderer.height);
if (this.glRenderer.shadowMap) this.glRenderer.shadowMap.enabled = this.rendererCfg.shadowMapEnabled;
this.setScene(sceneConfig);
this.camera = new THREE.PerspectiveCamera(this.cameraCfg.fov, this.cameraCfg.aspect, this.cameraCfg.near, this.cameraCfg.far);
this.setCamera(cameraConfig);
if (this.cfg.useOrbit) this.initOrbit(orbitCfg);
if (this.cfg.useTrackball) this.initTrackball(trackballCfg);
//if (this.cfg.useLeapCamera)
this.initLeapCamera(null);
this.raycaster = new THREE.Raycaster();
if(this.raycaster.setFromCamera) this.raycaster.setFromCamera(this.mousePosition, this.camera);
if (this.cfg.useCssRender) {
this.setCssRenderer();
}
let canvas = document.getElementById(this.cfg.canvasId);
while (canvas.firstChild) {
canvas.removeChild(canvas.firstChild);
}
if (this.cfg.useAsciiEffect) {
this.setAsciiEffect();
}
else if (this.cfg.useAnaglyphEffect) {
this.setAnaglyphEffect();
}
else if (this.cfg.useStereoEffect) {
this.setStereoEffect();
}
else if (this.cfg.useCssRender) {
canvas.appendChild(this.cssRenderer.domElement);
this.cssRenderer.domElement.appendChild(this.glRenderer.domElement);
}
else {
canvas.appendChild(this.glRenderer.domElement);
}
// this.projector = new THREE.Projector();
this.render();
if (this.cfg.useDatGui) {
this.initDatGui();
}
if (this.cfg.useStats) {
this.initStats();
}
}
render () {
if (this.cfg.useAsciiEffect && this.asciiEffect) {
this.asciiEffect.render(this.glScene, this.camera);
}
else if (this.cfg.useAnaglyphEffect && this.anaglyphEffect) {
this.anaglyphEffect.render(this.glScene, this.camera);
}
else if (this.cfg.useStereoEffect && this.stereoEffect) {
this.stereoEffect.render(this.glScene, this.camera);
}
else if (this.cfg.useCssRender) {
this.glRenderer.render(this.glScene, this.camera);
this.cssRenderer.render(this.cssScene, this.camera);
}
else {
this.glRenderer.render(this.glScene, this.camera);
}
}
setCamera(cameraCfg?: cfg.CameraCfg, orbitCfg?: cfg.OrbitCfg, trackballCfg?: cfg.TrackballCfg) {
if (cameraCfg) {
this.copyCfg(cameraCfg, this.cameraCfg);
}
this.camera.fov = this.cameraCfg.fov;
this.camera.aspect = this.cameraCfg.aspect;
this.camera.near = this.cameraCfg.near;
this.camera.far = this.cameraCfg.far;
this.camera.position.x = this.cameraCfg.position.x;
this.camera.position.y = this.cameraCfg.position.y;
this.camera.position.z = this.cameraCfg.position.z;
//this.camera.lookAt(this.scene.position); //new THREE.Vector3(10, 0, 0)); //scene.position);
this.cameraHelper = new THREE.CameraHelper(this.camera);
this.cameraHelper.update();
// this.add(this.cameraHelper, null, false, false);
this.cameraHelper.visible = this.cameraCfg.showHelper;
}
setScene(sceneCfg?: cfg.SceneCfg) {
if (this.glScene.fog) {
this.glScene.fog = null;
}
if (sceneCfg) {
this.copyCfg(sceneCfg, this.sceneCfg);
}
if (this.sceneCfg.useFog) {
this.setFog(this.sceneCfg);
}
if (this.grid) {
this.removeGridHelper();
}
if (this.sceneCfg.showGrid) {
this.addGridHelper(this.sceneCfg);
}
if (this.axis) {
this.removeAxisHelper();
}
if (this.sceneCfg.showAxis) {
this.addAxisHelper(this.sceneCfg);
}
}
convertHex (hex,opacity){
hex = hex.replace('#','');
let r = parseInt(hex.substring(0,2), 16);
let g = parseInt(hex.substring(2,4), 16);
let b = parseInt(hex.substring(4,6), 16);
let result = 'rgba(' + r + ',' + g + ',' + b + ',' + opacity / 100 + ')';
return result;
}
initStats () {
this.stats = new Stats();
this.stats.setMode(0);
this.stats.domElement.style.position = 'absolute';
this.stats.domElement.style.left = '0px';
this.stats.domElement.style.top = '0px';
let statsElem = document.getElementById(this.cfg.statsId);
if (statsElem) {
statsElem.appendChild(this.stats.domElement);
}
return this.stats;
}
initOrbit (cfg) {
if(cfg) {
this.copyCfg(cfg, this.orbitCfg);
}
// Orbit controls
this.orbitControls = new OrbitControls(this.camera, this.glRenderer.domElement);
this.orbitControls.minDistance = this.orbitCfg.minDistance;
this.orbitControls.maxDistance = this.orbitCfg.maxDistance;
}
initTrackball (cfg) {
if(cfg) {
this.copyCfg(cfg, this.trackballCfg);
}
this.trackballControls = new TrackballControls(this.camera, this.glRenderer.domElement);
this.trackballControls.rotateSpeed = this.trackballCfg.rotateSpeed;
this.trackballControls.zoomSpeed = this.trackballCfg.zoomSpeed;
this.trackballControls.panSpeed = this.trackballCfg.panSpeed;
this.trackballControls.noZoom = this.trackballCfg.noZoom;
this.trackballControls.noPan = this.trackballCfg.noPan;
this.trackballControls.staticMoving = this.trackballCfg.staticMoving;
this.trackballControls.dynamicDampingFactor = this.trackballCfg.dynamicDampingFactor;
this.trackballControls.target.set(0, 0, 0);
}
initLeapCamera (cfg) {
//if(cfg) {
// this.copyCfg(cfg, this.leapCfg);
//}
// Leap camera controls
this.leapCameraControls = new leapControls.LeapCameraControls(this.camera);
}
initDatGui () {
this.guiControls = new function() {
//this.prop = 0;
}
this.datGui = new dat.GUI();
//datGui.add(controls, 'prop', 0, 0.5);
return this.guiControls;
}
addGuiFolder (name) {
var folder = this.datGui.addFolder(name);
return folder;
}
addGuiProp(folder, propName, value, min?, max?, values?) {
this.guiControls[propName] = !cfg.U.isEmpty(value) ? value : '';
if (folder) {
if (!cfg.U.isEmpty(min) && !cfg.U.isEmpty(max))
return folder.add(this.guiControls, propName, min, max);
if (!cfg.U.isEmpty(min))
return folder.add(this.guiControls, propName, min);
if (values && values.length > 0)
return folder.add(this.guiControls, propName, values);
return folder.add(this.guiControls, propName);
}
else {
return this.datGui.add(this.guiControls, propName, min, max);
}
}
addGuiColorProp (folder, propName, value) {
this.guiControls[propName] = value;
if(folder) {
return folder.addColor(this.guiControls, propName);
}
else {
return this.datGui.add(this.guiControls, propName);
}
}
addGuiMethod(folder, methodName) {
let wglUtil: WglUtil = this;
if(folder) {
return folder.add(this.guiControls, methodName);
}
else {
return this.datGui.add(this.guiControls, methodName);
}
}
addGuiButton(folder, name, handler) {
let obj = {};
let wglUtil: WglUtil = this;
let parent = this.parent;
obj[name] = () => {
handler(wglUtil, parent);
}
if(folder) {
return folder.add(obj, name);
}
else {
return this.datGui.add(obj, name);
}
}
addGuiPropValues (folder, propName, value, values) {
this.guiControls[propName] = value;
if(folder) {
return folder.add(this.guiControls, propName, values);
}
else {
return this.datGui.add(this.guiControls, propName, values);
}
}
refreshGui() {
WglUtil.refreshDatGui(this.datGui);
/*
for (var i = 0; i < Object.keys(this.datGui.__folders).length; i++) {
var key = Object.keys(this.datGui.__folders)[i];
for (var j = 0; j < this.datGui.__folders[key].__controllers.length; j++) {
this.datGui.__folders[key].__controllers[j].updateDisplay();
}
}
*/
}
static refreshDatGui(datGui: dat.GUI) {
for (var i = 0; i < Object.keys(datGui.__folders).length; i++) {
var key = Object.keys(datGui.__folders)[i];
for (var j = 0; j < datGui.__folders[key].__controllers.length; j++) {
datGui.__folders[key].__controllers[j].updateDisplay();
}
}
}
getGuiFolder(folderName: string) {
for (var i = 0; i < Object.keys(this.datGui.__folders).length; i++) {
var key = Object.keys(this.datGui.__folders)[i];
if (key === folderName) {
return this.datGui.__folders[i];
}
}
return null;
}
getGuiController(folderName: string, propName: string) {
let folder = this.getGuiFolder(folderName);
if (folder) {
for (var j = 0; j < folder.__controllers.length; j++) {
if (folder.__controllers[j].property === propName) {
return folder.__controllers[j];
}
}
}
return null;
}
removeDatGuiFolder(name: string) {
WglUtil.removeDatGuiFolder(this.datGui, name);
}
static removeDatGuiFolder(datGui: dat.GUI, name: string) {
let folder = datGui.__folders[name];
if (!folder) {
return;
}
folder.close();
datGui.__ul.removeChild(folder.domElement.parentNode);
delete datGui.__folders[name];
datGui.onResize();
}
addAxisHelper(sceneCfg?: cfg.SceneCfg) {
if (this.axis) {
this.removeAxisHelper();
}
if (sceneCfg) {
this.copyCfg(sceneCfg, this.sceneCfg);
}
this.axis = new THREE.AxisHelper(this.sceneCfg.axisSize);
this.glScene.add(this.axis);
if (this.sceneCfg.useAxisArrows) {
this.axisArrowX = this.addAxisArrow({ x: 1, y: 0, z: 0 });
this.axisArrowY = this.addAxisArrow({ x: 0, y: 1, z: 0 });
this.axisArrowZ = this.addAxisArrow({ x: 0, y: 0, z: 1 });
}
}
addAxisArrow(axis: cfg.XYZ) {
if (this.sceneCfg.useAxisArrows) {
let dir = new THREE.Vector3(axis.x, axis.y, axis.z);
let origin = new THREE.Vector3(0, 0, 0);
let length = this.sceneCfg.axisSize;
let hex = 0xffffff;
if (axis.x) hex = 0xff0000;
if (axis.y) hex = 0x00ff00;
if (axis.z) hex = 0x0000ff;
let headLength = this.sceneCfg.axisArrowHeadLength;
let arrowHelper = new THREE.ArrowHelper(dir, origin, length, hex, headLength);
this.glScene.add(arrowHelper);
return arrowHelper;
}
}
removeAxisHelper() {
if (this.axis) {
this.remove(this.axis);
this.remove(this.axisArrowX);
this.remove(this.axisArrowY);
this.remove(this.axisArrowZ);
this.axis = null;
}
}
addDirLight (cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.dirLightCfg);
}
let dirLightHelper = this.genDirLight(cfg);
this.add(dirLightHelper.light, group);
this.add(dirLightHelper, group);
return dirLightHelper;
}
addPointLight(cfg?, group?) {
if(cfg) {
this.copyCfg(cfg, this.pointLightCfg);
}
var pointLightHelper = this.genPointLight(cfg);
this.add(pointLightHelper.light, group);
this.add(pointLightHelper, group);
return pointLightHelper;
}
addHemisphereLight (cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.hemisphereLightCfg);
}
let hemisphereLightHelper = this.genHemisphereLight(cfg);
this.add(hemisphereLightHelper.light, group);
this.add(hemisphereLightHelper, group);
return hemisphereLightHelper;
}
addSpotLight(cfg?, group?) {
if(cfg) {
this.copyCfg(cfg, this.spotLightCfg);
}
var spotLightHelper = this.genSpotLight(cfg);
this.add(spotLightHelper.light, group);
this.add(spotLightHelper, group);
return spotLightHelper;
}
getJson(group: any): any {
let json: any = {};
try {
if (group) {
json = group.toJSON();
}
else {
json = this.glScene.toJSON();
}
}
catch (e) {
json = { error: e };
}
return json;
}
onContentChanged(object, group, type: ContentChangedType) {
let json = this.getJson(group);
let canvas = document.getElementById(this.cfg.canvasId);
if (!canvas) return;
let args: WglUtilContentChangedArgs = new WglUtilContentChangedArgs();
args.group = group;
args.object = object;
args.json = json;
args.type = type;
this.contentChanged = new CustomEvent('contentChanged', { 'detail': args });
canvas.dispatchEvent(this.contentChanged);
}
add(obj, group?, raiseContentChanged: boolean = true, isSelectable: boolean = true) {
if (group) {
group.add(obj);
}
else {
this.glScene.add(obj);
}
if (isSelectable) {
this.objects.push(obj);
if (obj.children.length > 0) {
for (let child of obj.children) {
this.objects.push(child);
}
}
this.initLeapObjectControls(obj);
}
if (raiseContentChanged) {
this.onContentChanged(obj, group, ContentChangedType.add);
}
}
addLight(lightHelper, group?, raiseContentChanged: boolean = true, isSelectable: boolean = true) {
if (lightHelper) {
this.add(lightHelper.light, group, raiseContentChanged, isSelectable);
if (lightHelper.visible) {
this.add(lightHelper, group, raiseContentChanged, isSelectable);
}
}
}
remove(obj, group?, raiseContentChanged: boolean = true) {
if (group) {
group.remove(obj);
}
else {
this.glScene.remove(obj);
}
if (obj.geometry && obj.geometry.dispose) obj.geometry.dispose();
if (obj.material) {
if (obj.material.type !== 'MultiMaterial') {
if (obj.material.dispose) obj.material.dispose();
}
else {
for (let mat of obj.material.materials) {
if (mat.dispose) mat.dispose();
}
}
}
let index: number = this.objects.indexOf(obj);
if (index >= 0) {
this.objects.splice(index, 1);
}
delete obj.userData;
obj = null;
if (raiseContentChanged) {
this.onContentChanged(obj, group, ContentChangedType.delete);
}
}
removeLight(lightHelper, group?, raiseContentChanged: boolean = true) {
if (lightHelper) {
this.remove(lightHelper.light, group, raiseContentChanged);
this.remove(lightHelper, group, raiseContentChanged);
}
}
clear(group?) {
let container = group ? group : this.glScene;
while (container.children.length > 0) {
container.remove(container.children[container.children.length - 1]);
}
this.onContentChanged(null, group, ContentChangedType.clear);
}
genPlaneGeom(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.planeCfg);
}
var geomPlane = new THREE.PlaneGeometry(this.planeCfg.width, this.planeCfg.height, this.planeCfg.widthSegments, this.planeCfg.heightSegments);
return geomPlane;
}
genCircleGeom(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.circleCfg);
}
let geomCircle: THREE.CircleGeometry;
if (this.circleCfg.thetaStart && this.circleCfg.thetaLength) {
geomCircle = new THREE.CircleGeometry(this.circleCfg.radius, this.circleCfg.segments, this.circleCfg.thetaStart, this.circleCfg.thetaLength);
}
else {
geomCircle = new THREE.CircleGeometry(this.circleCfg.radius, this.circleCfg.segments);
}
return geomCircle;
}
genCubeGeom(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.cubeCfg);
}
var geomCube = new THREE.BoxGeometry(this.cubeCfg.width, this.cubeCfg.height, this.cubeCfg.depth);
if (this.cubeCfg.widthSegments) {
geomCube.parameters.widthSegments = this.cubeCfg.widthSegments;
}
if (this.cubeCfg.heightSegments) {
geomCube.parameters.heightSegments = this.cubeCfg.heightSegments;
}
if (this.cubeCfg.depthSegments) {
geomCube.parameters.depthSegments = this.cubeCfg.depthSegments;
}
return geomCube;
}
genSphereGeom(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.sphereCfg);
}
let geomSphere: THREE.SphereGeometry;
if (this.sphereCfg.phiStart && this.sphereCfg.phiLength && this.sphereCfg.thetaStart && this.sphereCfg.thetaLength) {
geomSphere = new THREE.SphereGeometry(this.sphereCfg.radius, this.sphereCfg.widthSegments, this.sphereCfg.heightSegments,
this.sphereCfg.phiStart, this.sphereCfg.phiLength, this.sphereCfg.thetaStart, this.sphereCfg.thetaLength);
return geomSphere;
}
if (this.sphereCfg.phiStart && this.sphereCfg.phiLength) {
geomSphere = new THREE.SphereGeometry(this.sphereCfg.radius, this.sphereCfg.widthSegments, this.sphereCfg.heightSegments,
this.sphereCfg.phiStart, this.sphereCfg.phiLength);
return geomSphere;
}
geomSphere = new THREE.SphereGeometry(this.sphereCfg.radius, this.sphereCfg.widthSegments, this.sphereCfg.heightSegments);
return geomSphere;
}
genCylinderGeom (cfg?) {
if(cfg) {
this.copyCfg(cfg, this.cylinderCfg);
}
var geomCylinder = new THREE.CylinderGeometry(this.cylinderCfg.radiusTop, this.cylinderCfg.radiusBottom, this.cylinderCfg.height,
this.cylinderCfg.radiusSegments, this.cylinderCfg.heightSegments,
this.cylinderCfg.openEnded, this.cylinderCfg.thetaStart, this.cylinderCfg.thetaLength);
//cylinderCfg.segmentsX, cylinderCfg.segmentsY);
geomCylinder.parameters.height = this.cylinderCfg.height;
return geomCylinder;
}
genTorusGeom(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.torusCfg);
}
var geomTorus = new THREE.TorusGeometry(this.torusCfg.radius, this.torusCfg.tube, this.torusCfg.radialSegments, this.torusCfg.tubularSegments, this.torusCfg.arc);
return geomTorus;
}
genTorusKnotGeom(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.torusKnotCfg);
}
var geomTorusKnot = new THREE.TorusKnotGeometry(this.torusKnotCfg.radius, this.torusKnotCfg.tube, this.torusKnotCfg.radialSegments, this.torusKnotCfg.tubularSegments, this.torusKnotCfg.p, this.torusKnotCfg.q);
return geomTorusKnot;
}
genLineGeom(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.lineCfg);
}
var geomLine = new THREE.BufferGeometry();
geomLine.vertices.push(
new THREE.Vector3(this.lineCfg.start.x, this.lineCfg.start.y, this.lineCfg.start.z),
new THREE.Vector3(this.lineCfg.end.x, this.lineCfg.end.y, this.lineCfg.end.z)
);
return geomLine;
}
genTextGeom(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.textCfg);
}
var textGeom = new THREE.TextGeometry(this.textCfg.text, {
size: this.textCfg.size,
height: this.textCfg.height,
curveSegments: this.textCfg.curveSegments,
font: this.textCfg.font,
// weight: this.textCfg.weight,
// style: this.textCfg.style,
bevelThickness: this.textCfg.bevelThickness,
bevelSize: this.textCfg.bevelSize,
bevelEnabled: this.textCfg.bevelEnabled,
// material: this.textCfg.material,
// extrudeMaterial: this.textCfg.extrudeMaterial
});
textGeom.computeBoundingBox();
textGeom.computeVertexNormals();
this.textCfg.geometry = textGeom;
// 'fix' side normals by removing z-component of normals for side faces
// (this doesn't work well for beveled geometry as then we lose nice curvature around z-axis)
if (!this.textCfg.bevelEnabled) {
console.log('bevel disabled not yet supported');
return textGeom;
/*
var triangleAreaHeuristics = 0.1 * (this.textCfg.height * this.textCfg.size);
for (var i = 0; i < textGeom.faces.length; i++) {
var face = textGeom.faces[i];
if (face.materialIndex == 1) {
for (var j = 0; j < face.vertexNormals.length; j++) {
face.vertexNormals[j].z = 0;
face.vertexNormals[j].normalize();
}
var va = textGeom.vertices[face.a];
var vb = textGeom.vertices[face.b];
var vc = textGeom.vertices[face.c];
var s = THREE.GeometryUtils.triangleArea(va, vb, vc);
if (s > triangleAreaHeuristics) {
for (var j = 0; j < face.vertexNormals.length; j++) {
face.vertexNormals[j].copy(face.normal);
}
}
}
}
*/
}
return textGeom;
}
genParticleGeom(cfg?) {
if (cfg) {
this.copyCfg(cfg, this.particleCfg);
}
var geom = new THREE.BufferGeometry();
var range = this.particleCfg.range;
var vertices = [];
var colors = [];
for (var i = 0; i < this.particleCfg.count; i++) {
// var particle = new THREE.Vector3(
// Math.random() * range - range / 2,
// Math.random() * range - range / 2,
// Math.random() * range - range / 2
// );
let x = Math.random() * range - range / 2;
let y = Math.random() * range - range / 2;
let z = Math.random() * range - range / 2;
// particle.userData = 'Particle ' + i;
vertices.push(x, y, z);
var color = new THREE.Color(this.particleCfg.color);
color.setHSL(Math.random(), 1.0, 0.5);
colors.push(color.r, color.g, color.b);
}
geom.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
geom.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
return geom;
}
genMeshBasicMat(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.matCfg);
}
var matCube = new THREE.MeshBasicMaterial({ color: this.matCfg.color, wireframe: this.matCfg.wireframe });
return matCube;
}
genMeshLambertMat(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.matCfg);
}
var matCube = new THREE.MeshLambertMaterial({ color: this.matCfg.color, wireframe: this.matCfg.wireframe });
return matCube;
}
genMeshPhongMat(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.matCfg);
}
var matCube = new THREE.MeshPhongMaterial({ color: this.matCfg.color, wireframe: this.matCfg.wireframe });
return matCube;
}
genLineBasicMat(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.matCfg);
}
var matLine = new THREE.LineBasicMaterial({ color: this.matCfg.color });
return matLine;
}
genLineDashedMat(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.matCfg);
}
var matLine = new THREE.LineDashedMaterial({ color: this.matCfg.color });
return matLine;
}
genTextMat(cfg?) {
if(cfg) {
this.copyCfg(cfg, this.textCfg);
}
let mat = new THREE.MultiMaterial([
new THREE.MeshPhongMaterial({ color: this.textCfg.frontColor !== null ? this.textCfg.frontColor : Math.random() * 0xffffff, shading: THREE.FlatShading }), // front
new THREE.MeshPhongMaterial({ color: this.textCfg.sideColor !== null ? this.textCfg.sideColor : 0xffffff, shading: THREE.SmoothShading }) // side
]);
if (this.textCfg.textMaterial == null) {
this.textCfg.textMaterial = mat;
}
return mat;
}
genParticleMat(cfg?) {
if (cfg) {
this.copyCfg(cfg, this.particleCfg);
}
var material = new THREE.PointsMaterial({
size: this.particleCfg.size,
transparent: this.particleCfg.transparent,
opacity: this.particleCfg.opacity,
vertexColors: THREE.VertexColors,
sizeAttenuation: this.particleCfg.sizeAttenuation,
// color: color,
//, map: THREE.ImageUtils.loadTexture('assets/textures/heart2.png'),
blending: THREE.AdditiveBlending,
alphaTest: 0.5
});
// material.color = new THREE.Color(0xFF0000); // .setHSL( 1.0, 0.3, 0.7 );
return material;
}
genSpriteMat(cfg) {
if(cfg) {
this.copyCfg(cfg, this.spriteCfg);
}
let oCfg = {};
if(this.spriteCfg.map) oCfg['map'] = this.spriteCfg.map;
if(this.spriteCfg.color) oCfg['color'] = this.spriteCfg.color;
let mat = new THREE.SpriteMaterial(oCfg);
return mat;
}
genPointLight(cfg?) {
if (cfg) {
this.copyCfg(cfg, this.pointLightCfg);
}
var pointLight = new THREE.PointLight(this.pointLightCfg.color, this.pointLightCfg.intensity, this.pointLightCfg.distance);
pointLight.position.set(this.pointLightCfg.position.x, this.pointLightCfg.position.y, this.pointLightCfg.position.z);
this.pointLightCfg.helper = new THREE.PointLightHelper(pointLight, this.pointLightCfg.helperSphereSize);
this.pointLightCfg.helper.visible = this.pointLightCfg.showHelper;
return this.pointLightCfg.helper;
}
genDirLight(cfg?) {
if (cfg) {
this.copyCfg(cfg, this.dirLightCfg);
}
var dirLight = new THREE.DirectionalLight(this.dirLightCfg.color, this.dirLightCfg.intensity);
dirLight.position.set(this.dirLightCfg.position.x, this.dirLightCfg.position.y, this.dirLightCfg.position.z);
// dirLight.shadow.camera.fov = this.dirLightCfg.shadowCameraFov;
dirLight.castShadow = this.dirLightCfg.castShadow;
this.dirLightCfg.helper = new THREE.DirectionalLightHelper(dirLight, this.dirLightCfg.size);
this.dirLightCfg.helper.visible = this.dirLightCfg.showHelper;
return this.dirLightCfg.helper;
}
genHemisphereLight(cfg?) {
if (cfg) {
this.copyCfg(cfg, this.hemisphereLightCfg);
}
var hempisphereLight = new THREE.HemisphereLight(this.hemisphereLightCfg.skyColor, this.hemisphereLightCfg.groundColor, this.hemisphereLightCfg.intensity);
hempisphereLight.position.set(this.hemisphereLightCfg.position.x, this.hemisphereLightCfg.position.y, this.hemisphereLightCfg.position.z);
this.hemisphereLightCfg.helper = new THREE.HemisphereLightHelper(hempisphereLight, this.hemisphereLightCfg.helperSphereSize);
this.hemisphereLightCfg.helper.visible = this.hemisphereLightCfg.showHelper;
return this.hemisphereLightCfg.helper;
}
genSpotLight(cfg?) {
if (cfg) {
this.copyCfg(cfg, this.spotLightCfg);
}
var spotLight = new THREE.SpotLight(this.spotLightCfg.color, this.spotLightCfg.intensity, this.spotLightCfg.distance);
spotLight.position.set(this.spotLightCfg.position.x, this.spotLightCfg.position.y, this.spotLightCfg.position.z);
this.spotLightCfg.helper = new THREE.SpotLightHelper(spotLight);
this.spotLightCfg.helper.visible = this.spotLightCfg.showHelper;
return this.spotLightCfg.helper;
}
addLine(cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.lineCfg);
}
var geomLine = this.genLineGeom(cfg);
var matLine = this.genLineBasicMat(cfg);
var line = new THREE.Line(geomLine, matLine);
this.add(line, group);
return line;
}
addPlane(cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.planeCfg);
}
// var geomPlane = new THREE.PlaneBufferGeometry(this.planeCfg.width, this.planeCfg.height, this.planeCfg.widthSegments, this.planeCfg.heightSegments);
var geomPlane = this.genPlaneGeom(cfg);
var matPlane = this.genMeshBasicMat(cfg);
var plane = new THREE.Mesh(geomPlane, matPlane);
//plane.rotation.x = -0.5 * Math.PI;
plane.position.x = this.planeCfg.position.x;
plane.position.y = this.planeCfg.position.y;
plane.position.z = this.planeCfg.position.z;
plane.receiveShadow = this.planeCfg.receiveShadow;
this.add(plane, group);
return plane;
}
addCircle(cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.circleCfg);
}
var geomCircle = this.genCircleGeom(cfg);
var matCircle = this.genMeshBasicMat(cfg);
var circle = new THREE.Mesh(geomCircle, matCircle);
circle.position.x = this.circleCfg.position.x;
circle.position.y = this.circleCfg.position.y;
circle.position.z = this.circleCfg.position.z;
circle.castShadow = this.circleCfg.castShadow;
if (this.circleCfg.rotation) {
circle.rotation.x = this.circleCfg.rotation.x;
circle.rotation.y = this.circleCfg.rotation.y;
circle.rotation.z = this.circleCfg.rotation.z;
}
this.add(circle, group);
return circle;
}
addCube(cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.cubeCfg);
}
var geomCube = this.genCubeGeom(cfg); // new THREE.BoxGeometry(cubeCfg.width, cubeCfg.height, cubeCfg.depth);
var matCube = this.genMeshBasicMat(cfg);
var cube = new THREE.Mesh(geomCube, matCube);
cube.position.x = this.cubeCfg.position.x;
cube.position.y = this.cubeCfg.position.y;
cube.position.z = this.cubeCfg.position.z;
cube.castShadow = this.cubeCfg.castShadow;
if (this.cubeCfg.rotation) {
cube.rotation.x = this.cubeCfg.rotation.x;
cube.rotation.y = this.cubeCfg.rotation.y;
cube.rotation.z = this.cubeCfg.rotation.z;
}
this.add(cube, group);
return cube;
}
addSphere(cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.sphereCfg);
}
var geomSphere = this.genSphereGeom(cfg); // new THREE.SphereGeometry(sphereCfg.radius, sphereCfg.widthSegments, sphereCfg.heightSegments);
var matSphere = this.genMeshBasicMat(cfg);
var sphere = new THREE.Mesh(geomSphere, matSphere);
sphere.position.x = this.sphereCfg.position.x;
sphere.position.y = this.sphereCfg.position.y;
sphere.position.z = this.sphereCfg.position.z;
sphere.castShadow = this.sphereCfg.castShadow;
this.add(sphere, group);
return sphere;
}
addCylinder(cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.cylinderCfg);
}
var geomCylinder = this.genCylinderGeom(cfg);
var matCylinder = this.genMeshBasicMat(cfg);
var cylinder = new THREE.Mesh(geomCylinder, matCylinder);
cylinder.position.x = this.cylinderCfg.position.x;
cylinder.position.y = this.cylinderCfg.position.y;
cylinder.position.z = this.cylinderCfg.position.z;
cylinder.castShadow = this.cylinderCfg.castShadow;
this.add(cylinder, group);
return cylinder;
}
addTorus(cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.torusCfg);
}
var geomTorus = this.genTorusGeom(cfg);
var matTorus = this.genMeshBasicMat(cfg);
var torus = new THREE.Mesh(geomTorus, matTorus);
this.add(torus, group);
return torus;
}
addTorusKnot(cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.torusCfg);
}
var geomTorusKnot = this.genTorusKnotGeom(cfg);
var matTorusKnot = this.genMeshBasicMat(cfg);
var torusKnot = new THREE.Mesh(geomTorusKnot, matTorusKnot);
this.add(torusKnot, group);
return torusKnot;
}
addParticles(cfg, group?) {
if (cfg) {
this.copyCfg(cfg, this.particleCfg);
}
let geom = this.genParticleGeom(cfg);
let material = this.genParticleMat(cfg);
let system: THREE.Points = new THREE.Points(geom, material);
this.add(system, group);
return system;
}
addSprite(cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.spriteCfg);
}
var matSprite = this.genSpriteMat(cfg);
var sprite = new THREE.Sprite(matSprite);
sprite.position.x = this.spriteCfg.position.x;
sprite.position.y = this.spriteCfg.position.y;
sprite.position.z = this.spriteCfg.position.z;
this.add(sprite, group);
return sprite;
}
addTextSprite(spriteCfg: cfg.SpriteCfg, textureCfg: cfg.TextureCfg, group?) {
let texture = this.createCanvasTexture(null, textureCfg);
spriteCfg.map = texture;
let matSprite = this.genSpriteMat(spriteCfg);
let sprite = new THREE.Sprite(matSprite);
var textObject = new THREE.Object3D();
let textWidth = textureCfg.canvas.width;
let textHeight = textureCfg.canvas.height;
let fontSize = textureCfg.canvas.fontSize;
// textObject.textHeight = fontSize;
// textObject.textWidth = (textWidth / textHeight) * textObject.textHeight;
sprite.scale.set(textWidth / textHeight * fontSize, fontSize, 1);
// sprite.position.set(10,10,0);
textObject.add(sprite);
this.add(textObject, group);
sprite.position.x = spriteCfg.position.x;
sprite.position.y = spriteCfg.position.y;
sprite.position.z = spriteCfg.position.z;
// this.add(sprite, group);
// return textObject;
return sprite;
}
addMesh(geom, mat, group?) {
let mesh = new THREE.Mesh(geom, mat);
this.add(mesh, group);
return mesh;
}
addParticleMesh(geom, mat, group?) {
let particles = new THREE.Points(geom, mat);
this.add(particles, group);
return particles;
}
setAsciiEffect () {
this.asciiEffect = new AsciiEffect(this.glRenderer);
this.asciiEffect.setSize(window.innerWidth, window.innerHeight);
let canvas = document.getElementById(this.cfg.canvasId);
while (canvas.children.length > 0) {
canvas.removeChild(canvas.children[0]);
}
canvas.appendChild(this.asciiEffect.domElement);
}
setAnaglyphEffect () {
var width = window.innerWidth || 2;
var height = window.innerHeight || 2;
this.anaglyphEffect = new AnaglyphEffect(this.glRenderer, this.cfg.anaglyphFocalLength, window.innerWidth, window.innerHeight);
this.anaglyphEffect.setSize(width, height);
let canvas = document.getElementById(this.cfg.canvasId);
canvas.appendChild(this.glRenderer.domElement);
}
setStereoEffect() {
let width = window.innerWidth;
let height = window.innerHeight;
this.stereoEffect = new StereoEffect(this.glRenderer);
this.stereoEffect.eyeSeparation = 1;
this.stereoEffect.setSize(width, height);
let canvas = document.getElementById(this.cfg.canvasId);
canvas.appendChild(this.glRenderer.domElement);
}
unsetEffects() {
let width = window.innerWidth;
let height = window.innerHeight;
this.glRenderer.setViewport(0, 0, width, height);
}
setFog(sceneConfig) {
if (this.glScene.fog) {
this.glScene.fog;
this.glScene.fog = null;
}
if(sceneConfig) {
this.copyCfg(sceneConfig, this.sceneCfg);
}
if (this.sceneCfg.useFog) {
this.glScene.fog = new THREE.FogExp2(this.sceneCfg.fogColor, this.sceneCfg.fogMistDensity);
}
}
genPoints (numPoints, cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.pointsCfg);
}
var points = [];
for (var i = 0; i < numPoints; i++) {
var randomX = this.pointsCfg.offset.x + Math.round(Math.random() * this.pointsCfg.step.x);
var randomY = this.pointsCfg.offset.y + Math.round(Math.random() * this.pointsCfg.step.y);
var randomZ = this.pointsCfg.offset.z + Math.round(Math.random() * this.pointsCfg.step.z);
points.push(new THREE.Vector3(randomX, randomY, randomZ));
}
let spGroup = new THREE.Object3D(); // Group(); //Object3D();
var material = new THREE.MeshBasicMaterial(
{ color: this.pointsCfg.color, transparent: this.pointsCfg.transparent});
var spGeom = new THREE.SphereGeometry(this.pointsCfg.radius);
for(var i = 0; i < points.length; i++) {
var material = new THREE.MeshBasicMaterial(
{ color: this.pointsCfg.color, transparent: this.pointsCfg.transparent});
var point = points[i];
var spMesh = new THREE.Mesh(spGeom, material);
spMesh.position.x = point.x;
spMesh.position.y = point.y;
spMesh.position.z = point.z;
spGroup.add(spMesh);
}
this.add(spGroup, group);
return spGroup;
}
rotate (obj, rotationSpeed) {
if(typeof(rotationSpeed) === 'object') {
if(rotationSpeed.hasOwnProperty('x')) obj.rotation.x += rotationSpeed.x;
if(rotationSpeed.hasOwnProperty('y')) obj.rotation.y += rotationSpeed.y;
if(rotationSpeed.hasOwnProperty('z')) obj.rotation.z += rotationSpeed.z;
}
else {
if(typeof(rotationSpeed) === 'number') {
obj.rotation.x += rotationSpeed;
obj.rotation.y += rotationSpeed;
obj.rotation.z += rotationSpeed;
}
}
}
createTextureMaterial (imageFile, cfg) {
if(cfg) {
this.copyCfg(cfg, this.textureCfg);
}
var fileUrl;
if(imageFile.startsWith('http')) {
fileUrl = imageFile;
}
else {
fileUrl = this.textureCfg.srcDir + encodeURIComponent(imageFile);
}
var loader = new THREE.TextureLoader();
var texture = loader.load(fileUrl); //THREE.ImageUtils.loadTexture(fileUrl);
texture.minFilter = THREE.LinearFilter;
var mat = new THREE.MeshPhongMaterial();
mat.map = texture;
return mat;
}
createTextureMaterials (imageFiles, cfg) {
var materials = [];
for(var i = 0; i < imageFiles.length; i++) {
materials.push(this.createTextureMaterial(imageFiles[i], cfg));
}
if(imageFiles.length < 6) {
for(let i = imageFiles.length; i < 6; i++) {
materials.push(new THREE.MeshBasicMaterial());
}
}
var material = new THREE.MultiMaterial(materials);
return material;
}
createVideoTextureMaterial (imageFile, cfg) {
if(cfg) {
this.copyCfg(cfg, this.textureCfg);
}
var fileUrl;
if(imageFile.startsWith('http')) {
fileUrl = imageFile;
}
else {
fileUrl = this.textureCfg.srcDir + encodeURIComponent(imageFile);
}
var video = document.createElement('video');
video.width = this.textureCfg.width;
video.height = this.textureCfg.height;
video.autoplay = this.textureCfg.autoplay;
video.loop = this.textureCfg.loop;
video.src = fileUrl;
this.textureCfg.video = video;
if(cfg) cfg.video = video;
var texture = new THREE.VideoTexture(video);
texture.minFilter = THREE.LinearFilter;
this.textureCfg.texture = texture;
var mat = new THREE.MeshBasicMaterial({ map : texture });
return mat;
}
createCanvasTexture(imageFile: string, cfg: cfg.TextureCfg) {
if (cfg) {
this.copyCfg(cfg, this.textureCfg);
}
var canvas1 = document.createElement('canvas');
canvas1.width = this.textureCfg.canvas.width;
canvas1.height = this.textureCfg.canvas.height;
var context1 = canvas1.getContext('2d');
var fileUrl;
if (imageFile) {
if (imageFile.startsWith('http')) {
fileUrl = imageFile;
}
else {
fileUrl = this.textureCfg.srcDir + encodeURIComponent(imageFile);
}
var backgroundImage = new Image();
backgroundImage.src = fileUrl;
context1.drawImage(backgroundImage, 0, 0);
context1.fillRect(0, 0, canvas1.width, canvas1.height);
}
context1.fillStyle = this.textureCfg.canvas.backgroundColor; // this.convertHex(0xFF0000.toString(16), 100); //'rgba(255, 0, 0, 1)';
context1.fillRect(0, 0, canvas1.width, canvas1.height);
context1.font = this.textureCfg.canvas.font;
context1.fillStyle = this.textureCfg.canvas.textColor; //this.convertHex(textureCfg.canvas.textColor.toString(16), 100); //'rgba(255, 0, 0, 1)';
context1.textAlign = <CanvasTextAlign>this.textureCfg.canvas.textAlign;
context1.textBaseline = <CanvasTextBaseline>this.textureCfg.canvas.textBaseline;
/*
var textWidth = context1.measureText(this.textureCfg.canvas.text).width;
context1.fillText(this.textureCfg.canvas.text, (canvas1.width - textWidth) / 2, (canvas1.height + parseInt(this.textureCfg.canvas.font)) / 2);
*/
context1.fillText(this.textureCfg.canvas.text, canvas1.width / 2, canvas1.height / 2);
// canvas contents will be used for a texture
var texture1 = new THREE.Texture(canvas1);
texture1.generateMipmaps = false;
texture1.minFilter = THREE.LinearFilter;
//texture1.magFilter = THREE.LinearFilter;
texture1.needsUpdate = true;
return texture1;
}
createCanvasTextureMaterial(imageFile: string, cfg: cfg.TextureCfg) {
let texture1 = this.createCanvasTexture(imageFile, cfg);
var mat = new THREE.MeshPhongMaterial( { map: texture1, side:THREE.DoubleSide } );
mat.transparent = true;
return mat;
}
createMesh (geom, mat, imageFile, cfg) {
if(cfg) {
this.copyCfg(cfg, this.textureCfg);
}
if(!mat) {
mat = this.createTextureMaterial(imageFile, cfg);
}
var mesh = new THREE.Mesh(geom, mat);
mesh.position.x = this.textureCfg.position.x;
mesh.position.y = this.textureCfg.position.y;
mesh.position.z = this.textureCfg.position.z;
return mesh;
}
createParticleMesh (geom, mat) {
var particles = new THREE.Points(geom, mat);
return particles;
}
genShaderMaterial (cfg) {
if(cfg) {
this.copyCfg(cfg, this.shadersCfg);
}
let vShaderElem = document.getElementById(this.shadersCfg.vertexShaderId);
let vShader: string = '';
if (vShaderElem) vShader = vShaderElem.innerText;
let fShaderElem = document.getElementById(this.shadersCfg.fragmentShaderId);
let fShader: string = '';
if (fShaderElem) fShader = fShaderElem.innerText;
var mat = new THREE.ShaderMaterial({
uniforms: this.shadersCfg.uniforms,
//attributes: shadersCfg.attributes,
vertexShader: vShader,
fragmentShader: fShader,
//vertexColors: THREE.VertexColors,
//side: THREE.DoubleSide
});
return mat;
}
loadShaderFile (shaderFile, loadHandler) {
var fileUrl;
if(shaderFile.startsWith('http')) {
fileUrl = shaderFile;
}
else {
fileUrl = this.shadersCfg.srcDir + encodeURIComponent(shaderFile);
}
this.getUrl(fileUrl, (data) => {
if (loadHandler) {
loadHandler(data);
}
});
}
addSkyBoxFromFile(cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.skyBoxCfg);
}
var cubeMap = new THREE.CubeTexture([]);
cubeMap.format = THREE.RGBFormat;
var loader = new THREE.ImageLoader();
loader.load(this.skyBoxCfg.srcFile, (image) => {
let getSide = (x, y) => {
var size = this.skyBoxCfg.size ? this.skyBoxCfg.size : 1024;
var canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
var context = canvas.getContext('2d');
context.drawImage(image, - x * size, - y * size);
return canvas;
};
cubeMap.images[0] = getSide(2, 1); // px
cubeMap.images[1] = getSide(0, 1); // nx
cubeMap.images[2] = getSide(1, 0); // py
cubeMap.images[3] = getSide(1, 2); // ny
cubeMap.images[4] = getSide(1, 1); // pz
cubeMap.images[5] = getSide(3, 1); // nz
cubeMap.needsUpdate = true;
});
var cubeShader = THREE.ShaderLib['cube'];
cubeShader.uniforms['tCube'].value = cubeMap;
var skyBoxMaterial = new THREE.ShaderMaterial({
fragmentShader: cubeShader.fragmentShader,
vertexShader: cubeShader.vertexShader,
uniforms: cubeShader.uniforms,
depthWrite: false,
side: THREE.BackSide
});
var skyBox = new THREE.Mesh(
new THREE.BoxGeometry(this.skyBoxCfg.width, this.skyBoxCfg.height, this.skyBoxCfg.depth),
skyBoxMaterial
);
this.add(skyBox, group);
return skyBox;
}
addSkyBoxFromFiles(cfg, group?) {
if(cfg) {
this.copyCfg(cfg, this.skyBoxCfg);
}
var path = this.skyBoxCfg.srcDir;
var urls = [
path + this.skyBoxCfg.px, path + this.skyBoxCfg.nx,
path + this.skyBoxCfg.py, path + this.skyBoxCfg.ny,
path + this.skyBoxCfg.pz, path + this.skyBoxCfg.nz
];
var skyBox;
var cubeMap = new THREE.CubeTexture([]);
//var textureCube = THREE.ImageUtils.loadTextureCube(urls);
var loader = new THREE.CubeTextureLoader();
loader.load(urls, (textureCube) => {
//var material = new THREE.MeshBasicMaterial({ color: 0xffffff, envMap: textureCube });
cubeMap = textureCube;
var shader = THREE.ShaderLib['cube'];
shader.uniforms['tCube'].value = cubeMap;
var material = new THREE.ShaderMaterial({
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
uniforms: shader.uniforms,
side: THREE.BackSide
});
skyBox = new THREE.Mesh(new THREE.BoxGeometry(this.skyBoxCfg.width, this.skyBoxCfg.height, this.skyBoxCfg.depth), material);
this.add(skyBox, group);
});
//TODO: undefined, need to ensure it's valid object.
return skyBox;
}
loadObjModel (cfg, objModelFile, textureFile, onLoad, onProgress, onError) {
if(cfg) {
this.copyCfg(cfg, this.objModelCfg);
}
var manager = new THREE.LoadingManager();
manager.onProgress = (item, loaded, total) => {
//console.log( item, loaded, total );
};
var texture = new THREE.Texture();
var txetureLoader = new THREE.ImageLoader(manager);
txetureLoader.load(this.objModelCfg.srcDir + textureFile, (image) => {
texture.image = image;
// texture.anisotropy = this.glRenderer.getMaxAnisotropy();
texture.minFilter = THREE.LinearFilter;
texture.needsUpdate = true;
} );
var loader = new THREE.OBJLoader(manager);
loader.load(this.objModelCfg.srcDir + objModelFile, (object) => {
object.traverse((child) => {
if (child instanceof THREE.Mesh) {
child.material.map = texture;
child.material.shading = THREE.SmoothShading;
}
});
if(onLoad) {
onLoad(object);
}
}, (xhr) => {
if(onProgress) {
onProgress(xhr);
}
}, (xhr) => {
if(onError) {
onError(xhr);
}
});
}
/*
loadObjMtlModel (cfg, objModelFile, mtlFile, onLoad, onProgress, onError) {
if(cfg) {
this.copyCfg(cfg, this.objModelCfg);
}
THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );
var loader = new THREE.OBJMTLLoader();
loader.load(this.objModelCfg.srcDir + objModelFile, this.objModelCfg.srcDir + mtlFile, function(object) {
if(onLoad) {
onLoad(object);
}
}, function(xhr) {
if(onProgress) {
onProgress(xhr);
}
}, function(xhr) {
if(onError) {
onError(xhr);
}
});
}
*/
createText (cfg) {
if(cfg) {
this.copyCfg(cfg, this.textCfg);
}
let textGeom = this.genTextGeom(cfg);
let mat = this.genTextMat(cfg);
var centerOffset = -0.5 * (textGeom.boundingBox.max.x - textGeom.boundingBox.min.x);
var textMesh1 = new THREE.Mesh(textGeom, mat);
textMesh1.position.x = centerOffset + this.textCfg.offsetX;
textMesh1.position.y = this.textCfg.hover;
textMesh1.position.z = 0;
textMesh1.rotation.x = 0;
textMesh1.rotation.y = Math.PI * 2;
this.textCfg.textMesh = textMesh1;
if(cfg) cfg.textMesh = textMesh1;
if (this.textCfg.useMirror) {
var textMesh2 = new THREE.Mesh(textGeom, mat);
textMesh2.position.x = centerOffset + this.textCfg.offsetX;
textMesh2.position.y = -this.textCfg.hover;
textMesh2.position.z = this.textCfg.height;
textMesh2.rotation.x = Math.PI;
textMesh2.rotation.y = Math.PI * 2;
this.textCfg.textMeshMirror = textMesh2;
if(cfg) cfg.textMeshMirror = textMesh2;
}
return textMesh1;
}
createTextMaterial (color1, color2) {
var mat = new THREE.MultiMaterial([
new THREE.MeshPhongMaterial({ color: color1 ? color1 : Math.random() * 0xffffff, /*shading: THREE.FlatShading*/ }), // front
new THREE.MeshPhongMaterial({ color: color2 ? color2 : 0xffffff, /*shading: THREE.SmoothShading*/ }) // side
]);
return mat;
}
centerMeshX (mesh, offsetX) {
var geom = mesh.geometry;
var centerOffset = -0.5 * (geom.boundingBox.max.x - geom.boundingBox.min.x);
mesh.position.x = centerOffset + (offsetX ? offsetX : 0);
}
centerMeshY (mesh, offsetY) {
var geom = mesh.geometry;
var centerOffset = -0.5 * (geom.boundingBox.max.y - geom.boundingBox.min.y);
mesh.position.y = centerOffset + (offsetY ? offsetY : 0);
}
centerMeshZ (mesh, offsetZ) {
var geom = mesh.geometry;
var centerOffset = -0.5 * (geom.boundingBox.max.z - geom.boundingBox.min.z);
mesh.position.z = centerOffset + (offsetZ ? offsetZ : 0);
}
// window resize
windowResize () {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.glRenderer.setSize(window.innerWidth, window.innerHeight);
if(this.cfg.useCssRender) {
this.cssRenderer.setSize(window.innerWidth, window.innerHeight);
}
this.render();
}
addSelectedObjectBoxHelper(group?) {
if(this.dndSelectedObject) {
this.dndSelectedObjectBoxHelper = new THREE.BoxHelper(this.dndSelectedObject);
this.add(this.dndSelectedObjectBoxHelper, group, false, false);
}
}
removeSelectedObjectBoxHelper(group?) {
if(this.dndSelectedObjectBoxHelper) {
this.remove(this.dndSelectedObjectBoxHelper, group, false);
this.dndSelectedObjectBoxHelper = null;
}
}
updateSelectedObjectBoxHelper () {
if(this.dndSelectedObjectBoxHelper && this.dndSelectedObject) {
this.dndSelectedObjectBoxHelper.update(this.dndSelectedObject);
}
}
addBoxHelper(obj, group?) {
if (obj) {
let objBoxHelper = new THREE.BoxHelper(obj);
this.add(objBoxHelper, group, false, false);
return objBoxHelper;
}
return null;
}
removeBoxHelper(objBoxHelper, group?) {
if (objBoxHelper) {
this.remove(objBoxHelper, group, false);
}
}
updateBoxHelper(obj, objBoxHelper) {
if (obj && objBoxHelper) {
objBoxHelper.update(obj);
}
}
// mouse events
getMouseUpIntersects (event) {
var containerWidth = window.innerWidth;
var containerHeight = window.innerHeight;
var mouseVector = new THREE.Vector3(0, 0, 1);
mouseVector.x = 2 * (event.clientX / containerWidth) - 1;
mouseVector.y = 1 - 2 * (event.clientY / containerHeight);
var vector = new THREE.Vector3(mouseVector.x, mouseVector.y, 0.5).unproject(this.camera);
this.raycaster.ray.set(this.camera.position, vector.sub(this.camera.position).normalize());
this.glScene.updateMatrixWorld();
var intersects = this.raycaster.intersectObjects(this.glScene.children, true);
return intersects;
}
dndMouseMove(event, moveObject: boolean = true, changePointer: boolean = true) { // , objects) {
event.preventDefault();
this.mousePosition.x = (event.clientX / window.innerWidth) * 2 - 1;
this.mousePosition.y = -(event.clientY / window.innerHeight) * 2 + 1;
this.raycaster.setFromCamera(this.mousePosition, this.camera);
if (this.dndSelectedObject) {
if (moveObject && this.raycaster.ray.intersectPlane(this.dndPlane, this.dndIntersection)) {
this.dndSelectedObject.position.copy(this.dndIntersection.sub(this.dndOffset));
}
return;
}
var intersects = this.raycaster.intersectObjects(this.objects); // .filter(item => item.visible);
let canvasElem = document.getElementById(this.cfg.canvasId);
if (intersects.length > 0) {
if (this.dndIntersectedObject != intersects[0].object) {
/*
if (this.dndIntersectedObject && this.dndIntersectedObject.material.color && this.dndIntersectedObject.currentHex) {
this.dndIntersectedObject.material.color.setHex(this.dndIntersectedObject.currentHex);
}
*/
this.setIntersectedObjectColor();
this.dndIntersectedObject = intersects[0].object;
if (this.dndIntersectedObject.material.color) {
this.dndIntersectedObject.currentHex = this.dndIntersectedObject.material.color.getHex();
}
if (moveObject) {
this.dndPlane.setFromNormalAndCoplanarPoint(
this.camera.getWorldDirection(this.dndPlane.normal),
this.dndIntersectedObject.position);
}
}
if (canvasElem && changePointer) {
canvasElem.style.cursor = 'pointer';
}
} else {
/*
if (this.dndIntersectedObject && this.dndIntersectedObject.material.color && this.dndIntersectedObject.currentHex) {
let color = this.dndIntersectedObject.material.color;
color.setHex(this.dndIntersectedObject.currentHex);
this.dndIntersectedObject.material.color = color;
}
*/
this.setIntersectedObjectColor();
this.dndIntersectedObject = null;
if (canvasElem) {
canvasElem.style.cursor = 'auto';
}
}
}
private setIntersectedObjectColor() {
if (this.dndIntersectedObject && this.dndIntersectedObject.material.color && this.dndIntersectedObject.currentHex) {
let color = this.dndIntersectedObject.material.color;
if (color.setHex) {
color.setHex(this.dndIntersectedObject.currentHex);
this.dndIntersectedObject.material.color = color;
}
}
}
dndMouseDown (event) { // , objects) {
event.preventDefault();
this.raycaster.setFromCamera(this.mousePosition, this.camera);
var intersects = this.raycaster.intersectObjects(this.objects); // .filter(item => item.visible);
if (intersects.length > 0) {
if (this.cfg.useTrackball && this.trackballControls) this.trackballControls.enabled = false;
this.dndSelectedObject = intersects[0].object;
if (this.raycaster.ray.intersectPlane(this.dndPlane, this.dndIntersection)) {
this.dndOffset.copy(this.dndIntersection).sub(this.dndSelectedObject.position);
}
let canvasElem = document.getElementById(this.cfg.canvasId);
if (canvasElem) {
canvasElem.style.cursor = 'move';
}
}
}
dndMouseUp (event) {
event.preventDefault();
if (this.cfg.useTrackball && this.trackballControls) this.trackballControls.enabled = true;
if (this.dndIntersectedObject) {
this.dndSelectedObject = null;
}
let canvasElem = document.getElementById(this.cfg.canvasId);
if (canvasElem) {
canvasElem.style.cursor = 'auto';
}
}
static rgbToHex (R,G,B) {
return this.toHex(R) + this.toHex(G) + this.toHex(B);
}
static hexToRgb (h) {
var r = this.hexToR(h);
var g = this.hexToG(h);
var b = this.hexToB(h);
return { r: r, g: g, b: b };
}
static hexToR(h) {
return parseInt(this.cutHex(h).substring(0, 2), 16)
}
static hexToG(h) {
return parseInt(this.cutHex(h).substring(2, 4), 16)
}
static hexToB(h) {
return parseInt(this.cutHex(h).substring(4, 6), 16)
}
static cutHex(h) {
return (h.charAt(0) == '#') ? h.substring(1, 7) : h
}
static toHex (n) {
n = parseInt(n,10);
if (isNaN(n)) return '00';
n = Math.max(0,Math.min(n,255));
return '0123456789ABCDEF'.charAt((n-n%16)/16)
+ '0123456789ABCDEF'.charAt(n%16);
}
static getColorFromRgb(value: { r: any, g: any; b: any }) {
let r = value.r; if (isNaN(r)) r = 0;
let g = value.g; if (isNaN(g)) g = 0;
let b = value.b; if (isNaN(b)) b = 0;
let color: THREE.Color = new THREE.Color(`rgb(${r}, ${g}, ${b})`);
return color;
}
static getColorFromHex(value: string) {
let rgb: { r: any, g: any; b: any } = this.hexToRgb(value);
return this.getColorFromRgb(rgb);
}
static isRGB(value: any): boolean {
if (!value) return false;
return !cfg.U.isEmpty(value.r) && !cfg.U.isEmpty(value.g) && !cfg.U.isEmpty(value.b);
}
static getColor(value: any): THREE.Color {
if (!value) return 0xFFFFFF;
if (this.isRGB(value)) {
return '#' + this.rgbToHex(value.r, value.g, value.b);
}
return value;
}
static getThreeColor(value: any): number {
if (!value) return new THREE.Color();
if (this.isRGB(value)) {
return this.getColorFromRgb(value);
}
return this.getColorFromHex(value);
}
genPointsMeshFromGeometry (geometry, cfg, group?) {
if (cfg) {
this.copyCfg(cfg, this.pointsFromGeomCfg);
}
var geom = geometry; // new THREE.BufferGeometry().fromGeometry(geometry);
var pointsMat = new THREE.PointsMaterial({ size: this.pointsFromGeomCfg.size, color: this.pointsFromGeomCfg.color });
let pointsMesh = new THREE.Points(geom, pointsMat);
pointsMesh.scale.x = pointsMesh.scale.y = pointsMesh.scale.z = this.pointsFromGeomCfg.scale;
pointsMesh.updateMatrix();
pointsMesh.visible = true;
this.add(pointsMesh, group);
return pointsMesh;
}
genPointsMeshFromMesh (mesh, cfg, group?) {
// var geom = new THREE.Geometry().fromBufferGeometry(mesh.geometry);
var geom = mesh.geometry.toBufferGeometry();
var pointsMesh = this.genPointsMeshFromGeometry(geom, cfg, group);
pointsMesh.position.set(mesh.position.x, mesh.position.y, mesh.position.z);
return pointsMesh;
}
toggleMeshMaterials (mesh, visible) {
mesh.material.transparent = true;
mesh.material.opacity = visible ? 1 : 0;
if (mesh.material.materials) {
for (var i = 0; i < mesh.material.materials.length; i++) {
mesh.material.materials[i].opacity = visible ? 1 : 0;
mesh.material.materials[i].transparent = true;
}
}
}
addGridHelper(cfg?: cfg.SceneCfg) {
if (this.grid) {
this.removeGridHelper();
}
if (cfg) {
this.copyCfg(cfg, this.sceneCfg);
}
this.grid = new THREE.GridHelper(this.sceneCfg.gridSize, this.sceneCfg.gridDivisions, this.sceneCfg.gridColorCenterLine, this.sceneCfg.gridColor);
this.add(this.grid, null, false, false);
return this.grid;
}
removeGridHelper() {
if (this.grid) {
this.remove(this.grid);
this.grid = null;
}
}
addGroup(group?) {
let newGroup = new THREE.Group();
this.add(newGroup, group);
return newGroup;
}
getObjectFromJson(objJson, geometries, materials) {
}
transform(tipPosition, w, h) {
let width = 150; // ???
let height = 150; // ???
let minHeight = 100; // ???
let ftx = tipPosition[0];
let fty = tipPosition[1];
ftx = (ftx > width ? width - 1 : (ftx < -width ? -width + 1 : ftx));
fty = (fty > 2 * height ? 2 * height - 1 : (fty < minHeight ? minHeight + 1 : fty));
let x = THREE.Math.mapLinear(ftx, -width, width, 0, w);
let y = THREE.Math.mapLinear(fty, 2 * height, minHeight, 0, h);
return [x, y];
};
leapFocusObject(frame) {
let hl = frame.hands.length;
let fl = frame.pointables.length;
console.log('hl', hl);
console.log('fl', fl);
if (hl == 1 && fl == 1) {
let f = frame.pointables[0];
let container: HTMLElement = this.glRenderer.domElement;
let width = container.clientWidth;
let height = container.clientHeight;
let coords = this.transform(f.tipPosition, width, height);
let vpx = (coords[0] / width) * 2 - 1;
let vpy = -(coords[1] / height) * 2 + 1;
let vector = new THREE.Vector3(vpx, vpy, 0.5);
// this.projector.unprojectVector(vector, this.camera);
let raycaster = new THREE.Raycaster(this.camera.position, vector.sub(this.camera.position).normalize());
let intersects = raycaster.intersectObjects(this.objects);
if (intersects.length > 0) {
let i = 0;
while (!intersects[i].object.visible) i++;
let intersected = intersects[i];
this.addBoxHelper(intersected);
return this.objects.indexOf(intersected.object);
} else {
return -1;
};
};
return -2;
}
initLeapObjectControls(threeObj: any) {
let objectControls = new leapControls.LeapObjectControls(this.camera, threeObj);
objectControls.rotateEnabled = true;
objectControls.rotateSpeed = 3;
objectControls.rotateHands = 1;
objectControls.rotateFingers = [2, 3];
objectControls.scaleEnabled = true;
objectControls.scaleSpeed = 3;
objectControls.scaleHands = 1;
objectControls.scaleFingers = [4, 5];
objectControls.panEnabled = true;
objectControls.panSpeed = 3;
objectControls.panHands = 2;
objectControls.panFingers = [6, 12];
objectControls.panRightHanded = false; // for left-handed person
this.leapObjectsControls.push(objectControls);
}
leapSelectObject(frame) {
let hl = frame.hands.length;
let fl = frame.pointables.length;
if (hl == 1 && fl == 1) {
let f = frame.pointables[0];
let container: HTMLElement = this.glRenderer.domElement;
let width = container.clientWidth;
let height = container.clientHeight;
let coords = this.transform(f.tipPosition, width, height);
} else {
}
}
objectsOverlap(obj1: THREE.Object3D, obj2: THREE.Object3D): boolean {
if(!obj1 || !obj2 || !obj1.geometry || !obj2.geometry) return false;
obj1.geometry.computeBoundingBox();
let box1 = obj1.geometry.boundingBox;
if (!box1) return false;
obj2.geometry.computeBoundingBox;
let box2 = obj2.geometry.boundingBox;
if (!box2) return false;
return box1.intersectsBox(box2);
}
checkObjectOverlap(threeObj: THREE.Object3D, otherObjs: THREE.Object3D[]) {
if(!threeObj || !otherObjs) return false;
for(let obj of otherObjs) {
if(obj.uuid !== threeObj.uuid) {
let overlap = this.objectsOverlap(threeObj, obj);
if(overlap) {
return true;
}
}
}
return false;
}
setMirrorCubeCamera(cfg) {
if (cfg) {
this.copyCfg(cfg, this.mirrorCubeCfg);
}
this.mirrorCubeCamera = new THREE.CubeCamera(this.mirrorCubeCfg.near, this.mirrorCubeCfg.far, this.mirrorCubeCfg.resolution);
// mirrorCubeCamera.renderTarget.minFilter = THREE.LinearMipMapLinearFilter;
this.mirrorCubeCamera.renderTarget.antialiasing = true;
this.glScene.add(this.mirrorCubeCamera);
return this.mirrorCubeCamera;
}
genMirrorCubeMat(cfg) {
if (!this.mirrorCubeCamera) {
this.setMirrorCubeCamera(cfg);
}
let mirrorCubeMat = new THREE.MeshBasicMaterial({ envMap: this.mirrorCubeCamera.renderTarget.texture });
return mirrorCubeMat;
}
addMirrorCube(cfg) {
if (cfg) {
this.copyCfg(cfg, this.mirrorCubeCfg);
}
this.setMirrorCubeCamera(cfg);
let cubeGeom = new THREE.CubeGeometry(this.mirrorCubeCfg.dimension.x, this.mirrorCubeCfg.dimension.y, this.mirrorCubeCfg.dimension.z, 1, 1, 1);
let mirrorCubeMat = this.genMirrorCubeMat(cfg);
this.mirrorCube = new THREE.Mesh(cubeGeom, mirrorCubeMat);
this.mirrorCube.position.set(this.mirrorCubeCfg.position.x, this.mirrorCubeCfg.position.y, this.mirrorCubeCfg.position.z);
let p = this.mirrorCube.position;
this.mirrorCubeCamera.position.set(p.x, p.y, p.z);
this.glScene.add(this.mirrorCube);
return this.mirrorCube;
}
updateMirrorCube() {
if (!this.mirrorCubeCamera || !this.mirrorCube) return;
this.mirrorCube.visible = false;
this.mirrorCubeCamera.updateCubeMap(this.glRenderer, this.glScene);
this.mirrorCube.visible = true;
}
createCssObject(w: number, h: number, position: THREE.Vector3, rotation: THREE.Vector3, url: string, id?: string) {
var id: string = id ? id : 'iframe1';
var html = `
<div id="div${id}" style="width:${w}px; height:${h}px;">
<iframe id="${id}" name="${id}" src="${url}" width="${w}" height="${h}"></iframe>
</div>
`;
let div: HTMLDivElement = document.createElement('div');
div.innerHTML = html;
let cssObject: css3d.CSS3DObject = new css3d.CSS3DObject(div);
cssObject.position.x = position.x;
cssObject.position.y = position.y;
cssObject.position.z = position.z;
cssObject.rotation.x = rotation.x;
cssObject.rotation.y = rotation.y;
cssObject.rotation.z = rotation.z;
return cssObject;
}
createCss3DPagePlane(w, h, position, rotation) {
let material = new THREE.MeshBasicMaterial({
color: 0x000000,
opacity: 0.0,
side: THREE.DoubleSide
});
let geometry = new THREE.PlaneGeometry(w, h);
let mesh = new THREE.Mesh(geometry, material);
mesh.position.x = position.x;
mesh.position.y = position.y;
mesh.position.z = position.z;
mesh.rotation.x = rotation.x;
mesh.rotation.y = rotation.y;
mesh.rotation.z = rotation.z;
return mesh;
}
create3dPage(w, h, position, rotation, url, id?: string, group?: any) {
let plane: THREE.Mesh = this.createCss3DPagePlane(w, h, position, rotation);
this.add(plane, group, true, true);
var cssObject = this.createCssObject(w, h, position, rotation, url, id);
this.cssScene.add(cssObject);
}
refresh3dPage(id: string, url?: string) {
if(!url || !id) return;
var div = document.getElementById(`div${id}`);
if(div && url) {
while(div.firstChild) {
div.removeChild(div.firstChild);
}
var w = div.style.width;
var h = div.style.height;
div.innerHTML = `<iframe id="${id}" name="${id}" src="${url}" width="${w}" height="${h}"></iframe>`;
}
}
setCssRenderer() {
this.cssRenderer = new css3d.CSS3DRenderer();
this.cssRenderer.setSize(window.innerWidth, window.innerHeight);
this.cssRenderer.domElement.style.position = 'absolute';
this.cssRenderer.domElement.style.top = 0;
this.glRenderer.domElement.style.position = 'absolute';
this.glRenderer.domElement.style.zIndex = 0;
this.glRenderer.domElement.style.top = 0;
this.cssScene = new THREE.Scene();
}
}