UNPKG

iv-3d-lib

Version:

A reusable ThreeJS library providing features for Ivee 3D Editor.

1,226 lines (1,219 loc) 85 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WglUtil = void 0; const THREE = require("three"); const dat = require("dat-gui"); const stats_1 = require("./stats"); const cfg = require("./wgl-util-cfgs"); const OrbitControls = require("three-orbitcontrols"); // import OrbitControls from 'three-orbitcontrols'; const TrackballControls = require("three-trackballcontrols"); // import TrackballControls from 'three-trackballcontrols'; const leapControls = require("threeleapcontrols"); const StereoEffect = require("three-stereoeffect"); const AnaglyphEffect = require("three-anaglypheffect"); const AsciiEffect = require("three-asciieffect"); const css3d = require("three-css3drenderer"); const wgl_util_content_changed_args_1 = require("./wgl-util-content-changed-args"); const OBJLoader_js_1 = require("three/examples/js/loaders/OBJLoader.js"); class WglUtil { constructor() { this.leapObjectsControls = []; this.objects = []; this.parent = null; this.mirrorCube = new THREE.Mesh; this.cameraCfg = { fov: 50, aspect: window.innerWidth / window.innerHeight, near: 0.1, far: 10000, position: { x: 200, y: 200, z: 200 } }; this.rendererCfg = { color: 0xFF0000, alpha: 0.5, width: window.innerWidth, height: window.innerHeight, shadowMapEnabled: true, antialias: true, useCanvas: false }; this.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 }; this.orbitCfg = { minDistance: -10000, maxDistance: 10000 }; this.trackballCfg = { rotateSpeed: 1.0, zoomSpeed: 1.2, panSpeed: 0.8, noZoom: false, noPan: false, staticMoving: true, dynamicDampingFactor: 0.3 }; this.lightCfg = { color: 0x0c0c0c, intensity: 0xffffff }; this.dirLightCfg = { color: 0xFFFFFF, intensity: 1.5, position: { x: 40, y: 60, z: -10 }, shadowCameraFov: 70, castShadow: true, showHelper: true, showHelperRuntime: false, size: 5 }; this.pointLightCfg = { color: 0x00FF00, intensity: 3, distance: 150, position: { x: 70, y: 5, z: 70 }, helperSphereSize: 3, showHelper: true, showHelperRuntime: false }; this.hemisphereLightCfg = { skyColor: 0xFFFFFF, groundColor: 0xFFFFFF, intensity: 1, position: { x: 40, y: 60, z: -10 }, showHelper: true, showHelperRuntime: false }; this.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 }; this.lineCfg = { start: { x: 0, y: 0, z: 0 }, end: { x: 10, y: 10, z: 10 }, color: Math.random() * 0xFFFFFF }; this.planeCfg = { width: 60, height: 20, widthSegments: 1, heightSegments: 1, color: Math.random() * 0xFFFFFF, position: { x: 0, y: 0, z: 0 }, receiveShadow: true }; this.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 } }; this.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 }; this.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 } }; this.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 } }; this.torusCfg = { radius: 8, tube: 4, radialSegments: 8, tubularSegments: 6, arc: 2 * Math.PI }; this.torusKnotCfg = { radius: 8, tube: 4, radialSegments: 8, tubularSegments: 6, p: 2, q: 3 }; this.pointsCfg = { color: Math.random() * 0xFFFFFF, radius: 0.2, transparent: true, offset: { x: -15, y: -15, z: -15 }, step: { x: 30, y: 30, z: 30 } }; this.pointsFromGeomCfg = { color: 0x000000, size: 0.1, scale: 1 }; this.particleCfg = { count: 100, size: 1, range: 500, transparent: true, opacity: 0.5, vertexColors: [], sizeAttenuation: true, color: 0xFF0000 }; this.textureCfg = { srcDir: 'assets/textures/', position: { x: 0, y: 0, z: 0 }, width: 100, height: 100, autoplay: true, loop: true, video: null, texture: null, canvas: { width: 200, height: 50, font: '24px Arial', text: '', textColor: '#000', backgroundColor: '#fff' } }; this.shadersCfg = { vertexShaderId: 'vertexShader', fragmentShaderId: 'fragmentShader', uniforms: {}, attributes: {}, srcDir: 'assets/shaders/glsl/' }; this.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 }; this.objModelCfg = { srcDir: 'assets/models/' }; this.textCfg = { text: '', height: 10, size: 50, hover: 30, curveSegments: 4, bevelEnabled: true, bevelThickness: 2, bevelSize: 1.5, bevelSegments: 3, font: 'optimer', weight: 'bold', style: 'normal', 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 } */ this.matCfg = { color: 0x000000, wireframe: false }; this.spriteCfg = { map: null, color: 0x000000 }; this.mirrorCubeCfg = { near: 0.1, far: 10000, resolution: 1024, dimension: { x: 4, y: 4, z: 1 }, position: { x: 100, y: 100, z: 100 } }; this.mousePosition = new THREE.Vector2(); this.dndPlane = new THREE.Plane(); this.dndOffset = new THREE.Vector3(); this.dndIntersection = new THREE.Vector3(); this.Android = () => { return navigator.userAgent.match(/Android/i); }; this.BlackBerry = () => { return navigator.userAgent.match(/BlackBerry/i); }; this.iOS = () => { return navigator.userAgent.match(/iPhone|iPad|iPod/i); }; this.Opera = () => { return navigator.userAgent.match(/Opera Mini/i); }; this.Windows = () => { return navigator.userAgent.match(/IEMobile/i); }; console.log(OBJLoader_js_1.OBJLoader); this.cfg = { 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; } copyCfg(srcCfg, destCfg) { for (let p in srcCfg) { if (destCfg.hasOwnProperty(p)) { destCfg[p] = srcCfg[p]; } } } isMobile() { 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()); } }; } static detectWebGL() { 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, value) { 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, cameraConfig, rendererConfig, orbitCfg, 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, orbitCfg, 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) { 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_1.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 = 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 = 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) { 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) { 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, propName) { 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) { WglUtil.removeDatGuiFolder(this.datGui, name); } static removeDatGuiFolder(datGui, name) { let folder = datGui.__folders[name]; if (!folder) { return; } folder.close(); datGui.__ul.removeChild(folder.domElement.parentNode); delete datGui.__folders[name]; datGui.onResize(); } addAxisHelper(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) { 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) { let json = {}; try { if (group) { json = group.toJSON(); } else { json = this.glScene.toJSON(); } } catch (e) { json = { error: e }; } return json; } onContentChanged(object, group, type) { let json = this.getJson(group); let canvas = document.getElementById(this.cfg.canvasId); if (!canvas) return; let args = new wgl_util_content_changed_args_1.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 = true, isSelectable = 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, wgl_util_content_changed_args_1.ContentChangedType.add); } } addLight(lightHelper, group, raiseContentChanged = true, isSelectable = true) { if (lightHelper) { this.add(lightHelper.light, group, raiseContentChanged, isSelectable); if (lightHelper.visible) { this.add(lightHelper, group, raiseContentChanged, isSelectable); } } } remove(obj, group, raiseContentChanged = 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 = this.objects.indexOf(obj); if (index >= 0) { this.objects.splice(index, 1); } delete obj.userData; obj = null; if (raiseContentChanged) { this.onContentChanged(obj, group, wgl_util_content_changed_args_1.ContentChangedType.delete); } } removeLight(lightHelper, group, raiseContentChanged = 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, wgl_util_content_changed_args_1.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; 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; 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, }); 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 }), 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 = 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, 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