diff --git a/src/renderer/component/viewers/threeViewer/index.jsx b/src/renderer/component/viewers/threeViewer/index.jsx index 63dc38622..0ceea09d5 100644 --- a/src/renderer/component/viewers/threeViewer/index.jsx +++ b/src/renderer/component/viewers/threeViewer/index.jsx @@ -4,6 +4,7 @@ import LoadingScreen from 'component/common/loading-screen'; // ThreeJS import * as THREE from './internal/three'; import detectWebGL from './internal/detector'; +import ThreeGrid from './internal/grid'; import ThreeScene from './internal/scene'; import ThreeLoader from './internal/loader'; import ThreeRenderer from './internal/renderer'; @@ -77,6 +78,12 @@ class ThreeViewer extends React.PureComponent { window.removeEventListener('resize', this.handleResize, false); } + transformGroup(group) { + this.fitMeshToCamera(group); + this.createWireFrame(group); + this.updateControlsTarget(group.position); + } + createOrbitControls(camera, canvas) { const { autoRotate } = this.props; const controls = new THREE.OrbitControls(camera, canvas); @@ -87,6 +94,7 @@ class ThreeViewer extends React.PureComponent { controls.minDistance = 1; controls.maxDistance = 50; controls.autoRotate = autoRotate; + controls.enablePan = false; return controls; } @@ -114,32 +122,6 @@ class ThreeViewer extends React.PureComponent { group.add(this.wireframe); } - createMesh(geometry) { - const material = new THREE.MeshPhongMaterial({ - opacity: 1, - transparent: true, - depthWrite: true, - vertexColors: THREE.FaceColors, - // Positive value pushes polygon further away - polygonOffsetFactor: 1, - polygonOffsetUnits: 1, - }); - - // Set material color - material.color.set(this.materialColors.green); - - const mesh = new THREE.Mesh(geometry, material); - - // Assign name - mesh.name = 'objectGroup'; - - this.scene.add(mesh); - this.fitMeshToCamera(mesh); - this.createWireFrame(mesh); - this.updateControlsTarget(mesh.position); - return mesh; - } - toggleWireFrame(show = false) { this.wireframe.opacity = show ? 1 : 0; this.mesh.material.opacity = show ? 0 : 1; @@ -151,7 +133,7 @@ class ThreeViewer extends React.PureComponent { group.traverse(child => { if (child instanceof THREE.Mesh) { - const box = new THREE.Box3().setFromObject(group); + const box = new THREE.Box3().setFromObject(child); // Max max.x = box.max.x > max.x ? box.max.x : max.x; max.y = box.max.y > max.y ? box.max.y : max.y; @@ -165,12 +147,18 @@ class ThreeViewer extends React.PureComponent { const meshY = Math.abs(max.y - min.y); const meshX = Math.abs(max.x - min.x); - const scaleFactor = 15 / Math.max(meshX, meshY); + + const scaleFactor = 10 / Math.max(meshX, meshY); group.scale.set(scaleFactor, scaleFactor, scaleFactor); group.position.setY((meshY / 2) * scaleFactor); + + // Reset object position + const box = new THREE.Box3().setFromObject(group); + box.getCenter(group.position); + group.position.multiplyScalar(-1); - group.position.setY((meshY * scaleFactor) / 2); + group.position.setY(group.position.y + meshY * scaleFactor); } startLoader() { @@ -217,12 +205,52 @@ class ThreeViewer extends React.PureComponent { this.controls.update(); } - renderModel(fileType, data) { + renderStl(data) { const geometry = this.createGeometry(data); - this.mesh = this.createMesh(geometry); + const group = new THREE.Mesh(geometry, this.material); + // Assign name + group.name = 'objectGroup'; + this.scene.add(group); + this.transformGroup(group); + this.mesh = group; + } + + renderObj(event) { + const mesh = event.detail.loaderRootNode; + const group = new THREE.Group(); + group.name = 'objGroup'; + + // Assign new material + mesh.traverse(child => { + if (child instanceof THREE.Mesh) { + // Get geometry from child + const geometry = new THREE.Geometry(); + geometry.fromBufferGeometry(child.geometry); + // Create and regroup inner objects + const innerObj = new THREE.Mesh(geometry, this.material); + group.add(innerObj); + } + }); + + this.scene.add(group); + this.transformGroup(group); + this.mesh = group; + } + + renderModel(fileType, parsedData) { + const renderTypes = { + stl: data => this.renderStl(data), + obj: data => this.renderObj(data), + }; + + if (renderTypes[fileType]) { + renderTypes[fileType](parsedData); + } } renderScene() { + const { gridColor, centerLineColor } = this.theme; + this.renderer = ThreeRenderer({ antialias: true, shadowMap: true, @@ -230,20 +258,40 @@ class ThreeViewer extends React.PureComponent { this.scene = ThreeScene({ showFog: true, - showGrid: true, ...this.theme, }); const viewer = this.viewer.current; const canvas = this.renderer.domElement; const { offsetWidth: width, offsetHeight: height } = viewer; + + // Grid + this.grid = ThreeGrid({ size: 100, gridColor, centerLineColor }); + this.scene.add(this.grid); + // Camera this.camera = new THREE.PerspectiveCamera(80, width / height, 0.1, 1000); this.camera.position.set(-9.5, 14, 11); + // Controls this.controls = this.createOrbitControls(this.camera, canvas); + // Set viewer size this.renderer.setSize(width, height); + + // Create model material + this.material = new THREE.MeshPhongMaterial({ + opacity: 1, + transparent: true, + // depthWrite: true, + vertexColors: THREE.FaceColors, + // Positive value pushes polygon further away + // polygonOffsetFactor: 1, + // polygonOffsetUnits: 1, + }); + // Set material color + this.material.color.set(this.materialColors.green); + // Load file and render mesh this.startLoader(); diff --git a/src/renderer/component/viewers/threeViewer/internal/grid.js b/src/renderer/component/viewers/threeViewer/internal/grid.js new file mode 100644 index 000000000..0793c6913 --- /dev/null +++ b/src/renderer/component/viewers/threeViewer/internal/grid.js @@ -0,0 +1,13 @@ +import { GridHelper, Color } from './three'; + +const ThreeGrid = ({ size, gridColor, centerLineColor }) => { + const divisions = size / 2; + const grid = new GridHelper(size, divisions, new Color(centerLineColor), new Color(gridColor)); + + grid.material.opacity = 0.4; + grid.material.transparent = true; + + return grid; +}; + +export default ThreeGrid; diff --git a/src/renderer/component/viewers/threeViewer/internal/loader.js b/src/renderer/component/viewers/threeViewer/internal/loader.js index dc4ce7482..d69a93344 100644 --- a/src/renderer/component/viewers/threeViewer/internal/loader.js +++ b/src/renderer/component/viewers/threeViewer/internal/loader.js @@ -1,4 +1,4 @@ -import { LoadingManager, STLLoader, OBJLoader } from './three'; +import { LoadingManager, STLLoader, OBJLoader2 } from './three'; const Manager = ({ onLoad, onStart, onError }) => { const manager = new LoadingManager(); @@ -12,7 +12,7 @@ const Manager = ({ onLoad, onStart, onError }) => { const Loader = (fileType, manager) => { const fileTypes = { stl: () => new STLLoader(manager), - obj: () => new OBJLoader(manager), + obj: () => new OBJLoader2(manager), }; return fileTypes[fileType] ? fileTypes[fileType]() : null; }; diff --git a/src/renderer/component/viewers/threeViewer/internal/scene.js b/src/renderer/component/viewers/threeViewer/internal/scene.js index f858c8832..a22c4a996 100644 --- a/src/renderer/component/viewers/threeViewer/internal/scene.js +++ b/src/renderer/component/viewers/threeViewer/internal/scene.js @@ -1,18 +1,5 @@ import * as THREE from './three'; -const addGrid = (scene, { gridColor, centerLineColor, size }) => { - const divisions = size / 2; - const grid = new THREE.GridHelper( - size, - divisions, - new THREE.Color(centerLineColor), - new THREE.Color(gridColor) - ); - grid.material.opacity = 0.4; - grid.material.transparent = true; - scene.add(grid); -}; - const addLights = (scene, color, groundColor) => { // Light color const lightColor = new THREE.Color(color); @@ -30,7 +17,7 @@ const addLights = (scene, color, groundColor) => { scene.add(shadowLight); }; -const Scene = ({ backgroundColor, groundColor, showFog, showGrid, gridColor, centerLineColor }) => { +const Scene = ({ backgroundColor, groundColor, showFog }) => { // Convert color const bgColor = new THREE.Color(backgroundColor); // New scene @@ -39,17 +26,8 @@ const Scene = ({ backgroundColor, groundColor, showFog, showGrid, gridColor, cen scene.background = bgColor; // Fog effect scene.fog = showFog === true ? new THREE.Fog(bgColor, 1, 95) : null; - // Add grid - if (showGrid) { - addGrid(scene, { - size: 100, - gridColor, - centerLineColor, - }); - } // Add basic lights addLights(scene, '#FFFFFF', groundColor); - // Return new three scene return scene; }; diff --git a/src/renderer/component/viewers/threeViewer/internal/three.js b/src/renderer/component/viewers/threeViewer/internal/three.js index 6cb0051d0..4e9f9bdb1 100644 --- a/src/renderer/component/viewers/threeViewer/internal/three.js +++ b/src/renderer/component/viewers/threeViewer/internal/three.js @@ -4,7 +4,8 @@ import * as THREE from 'three'; // Fix: https://github.com/mrdoob/three.js/issues/9562#issuecomment-383390251 global.THREE = THREE; require('three/examples/js/controls/OrbitControls'); -require('three/examples/js/loaders/OBJLoader'); +require('three/examples/js/loaders/LoaderSupport'); +require('three/examples/js/loaders/OBJLoader2'); require('three/examples/js/loaders/STLLoader'); module.exports = global.THREE;