diff --git a/app/Resources/assets/js/ModelViewer.js b/app/Resources/assets/js/ModelViewer.js index 09bc7cc..5604ee2 100644 --- a/app/Resources/assets/js/ModelViewer.js +++ b/app/Resources/assets/js/ModelViewer.js @@ -1,85 +1,215 @@ -ModelViewer = function() { - var container; - var camera, cameraTarget, scene, renderer, controls, object; - var width, height; +var ModelViewer = function($container) { + var $this = this; + this.container = $container; - this.initScene = function($container) { - width = parseFloat($container.width()); - height = parseFloat($container.height()); + this.camera = null; + this.scene = null; + this.renderer = null; + this.controls = null; + this.object = null; + this.width = parseFloat(this.container.width()); + this.height = parseFloat(this.container.height()); + this.visible = true; + this.scale = 1; - camera = new THREE.PerspectiveCamera(45, width/height, 0.1, 1000); - camera.position.set(-2, 2, 0.8); - camera.lookAt(new THREE.Vector3(0, 3, 0)); + this.initScene(); - scene = new THREE.Scene(); - scene.fog = new THREE.FogExp2(0x000000, 0.001); + function renderLoop() { + requestAnimationFrame( renderLoop ); + $this.render(); + } - // var grid = new THREE.GridHelper( 30, 70 ); - // // grid.position.set(30/70,-0.5,30/70); - // scene.add( grid ); + renderLoop(); +}; - // Lights +ModelViewer.prototype.initScene = function() { - light = new THREE.DirectionalLight( 0xffffff ); - light.position.set( 1, 1, 1 ); - scene.add( light ); + this.scene = new THREE.Scene(); - light = new THREE.DirectionalLight( 0x002288 ); - light.position.set( -1, -1, -1 ); - scene.add( light ); + this.camera = new THREE.PerspectiveCamera(45, this.width / this.height, 1, 1000); + this.camera.position.z = 8; + this.camera.position.y = -5; + this.camera.position.x = 3; + this.camera.up = new THREE.Vector3(0, 0, 1); + + this.reflectCamera = new THREE.CubeCamera(1, 50, 200); + this.scene.add(this.reflectCamera); + + var material = new THREE.MeshPhongMaterial({ + color: 0xffffff, + emissive: 0xffffff, + shading: THREE.SmoothShading, + fog: false, + side: THREE.BackSide + }); + + var skybox = new THREE.Mesh(new THREE.CubeGeometry(100, 100, 100), material); + skybox.name = 'skybox'; + this.scene.add(skybox); + + var groundPlaneMaterial = new THREE.MeshPhongMaterial({ + color: 0x888888, + wireframe: false, + transparent: true, + opacity: 0.25, + // fog: true, + // specular: 0x999999, + envMap: this.reflectCamera.renderTarget + }); + var x = 80; + var y = 80; + var division_x = Math.floor(x / 2); + var division_y = Math.floor(y / 2); + + this.plane = new THREE.Mesh(new THREE.PlaneGeometry(x, y, division_x, division_y), groundPlaneMaterial); + this.plane.name = 'plane'; + this.plane.receiveShadow = true; + this.scene.add(this.plane); + + this.grid = new THREE.GridHelper( 80, 100, 0xEEEEEE,0xEEEEEE); + this.grid.rotation.x = Math.PI/2; + + this.scene.add(this.grid); - scene.add( new THREE.AmbientLight( 0xf0f0f0 )); - scene.background = new THREE.Color( 0x000000 ); + // this.wirePlane = new THREE.Mesh(new THREE.PlaneGeometry(x, y, division_x, division_y), new THREE.MeshPhongMaterial({ + // emissive: 0xEEEEEE, + // color: 0x000000, + // wireframe: true, + // wireframeLinewidth: 2 + // })); + // this.wirePlane.name = 'planewire'; + // this.wirePlane.receiveShadow = true; + // this.wirePlane.position.z = this.plane.position.z + .01; + // this.scene.add(this.wirePlane); - // renderer - renderer = new THREE.WebGLRenderer(); - renderer.setClearColor( scene.fog.color ); - renderer.setPixelRatio( window.devicePixelRatio ); - renderer.setSize( width, height ); - renderer.gammaInput = true; - renderer.gammaOutput = true; - renderer.shadowMap.enabled = true; - renderer.shadowMap.renderReverseSided = false; + this.renderer = new THREE.WebGLRenderer(); - $container.append(renderer.domElement); + this.renderer.setSize(this.width, this.height); - controls = new THREE.OrbitControls( camera, renderer.domElement ); - controls.addEventListener( 'change', this.render ); // add this only if there is no animation loop (requestAnimationFrame) - // controls.enableDamping = true; - // controls.dampingFactor = 0.25; - controls.enableZoom = true; - }; + this.container.append(this.renderer.domElement); - this.loadStl = function(model) { - var loader = new THREE.STLLoader(); - loader.load(model, function (geometry) { - var material = new THREE.MeshPhongMaterial({color: 0xaaaaaa, shininess:200, specular: 0x333333, shading: THREE.FlatShading}); - var mesh = new THREE.Mesh(geometry, material); + this.scene.fog = new THREE.FogExp2(0xcacaca, 0.9); - mesh.geometry.computeBoundingBox(); - var positionY = (mesh.geometry.boundingBox.max.y + mesh.geometry.boundingBox.min.y)/2; + // // Light + this.spotLight = new THREE.SpotLight(0xffffff, 0.9, 0); + this.spotLight.position.set(-70, 100, 100); + this.spotLight.castShadow = false; + this.scene.add(this.spotLight); - // mesh.position.set(0, positionY, 0); - mesh.rotation.set(Math.PI, 0, 0); - mesh.castShadow = true; - mesh.receiveShadow = true; - scene.add(mesh); - - renderer.render(scene, camera); - }); - }; + this.bottomSpotLight = new THREE.SpotLight(0xffffff, 0.3, 0); + this.bottomSpotLight.position.set(70, -100, -100); + this.bottomSpotLight.castShadow = false; + this.scene.add(this.bottomSpotLight); - this.animate = function() { - requestAnimationFrame( this.animate ); - this.render(); - }; + this.pointLight = new THREE.PointLight(0xffaaff, 0.9, 0); + this.pointLight.position.set(32, -39, 35); + this.pointLight.castShadow = true; + this.scene.add(this.pointLight); - this.render = function() { + this.renderer.shadowMap.enabled = true; + this.renderer.shadowMap.renderReverseSided = false; - renderer.render(scene, camera); + // $container.append(this.renderer.domElement); - }; + this.controls = new THREE.OrbitControls( this.camera, this.renderer.domElement ); + this.controls.enableZoom = true; +}; + +ModelViewer.prototype.addModel = function(geometry) { + var material = new THREE.MeshPhongMaterial({ + color: 0x136FC3, + specular: 0x0D0D0D, + shading: THREE.SmoothShading, + shininess: 150, + fog: false, + side: THREE.DoubleSide, + // wireframe: true, + }); + + geometry.center(); + var mesh = new THREE.Mesh(geometry, material); + + mesh.scale.set(this.scale, this.scale, this.scale); + + mesh.geometry.computeFaceNormals(); + mesh.geometry.computeVertexNormals(); + mesh.rotation.set(-Math.PI/2,0, 0); + mesh.geometry.computeBoundingBox(); + + mesh.castShadow = true; + // mesh.receiveShadow = true; + + var dims = mesh.geometry.boundingBox.max.clone().sub(mesh.geometry.boundingBox.min); + + maxDim = Math.max(Math.max(dims.x, dims.y), dims.z); + + mesh.position.x = -(mesh.geometry.boundingBox.min.x + mesh.geometry.boundingBox.max.x) / 2 * this.scale; + mesh.position.z = -(mesh.geometry.boundingBox.min.y + mesh.geometry.boundingBox.max.y) / 2 * this.scale; + mesh.position.y = -mesh.geometry.boundingBox.min.z * this.scale; + + var positionY = (mesh.geometry.boundingBox.max.z + mesh.geometry.boundingBox.min.z)/2 * this.scale; + var positionZ = (mesh.geometry.boundingBox.max.y - mesh.geometry.boundingBox.min.y)/2 * this.scale; + + mesh.position.set(0, positionY, positionZ); + + // this.scene.face_count = mesh.geometry.faces.length; + this.scene.add(mesh); + + this.centerCamera(mesh); +}; + +ModelViewer.prototype.loadStl = function(model) { + var self = this; + + var loader = new THREE.STLLoader(); + + loader.load(model, function (geometry) { + self.addModel(geometry); + }); +}; + +ModelViewer.prototype.centerCamera = function(mesh) { + + var boxHelper = new THREE.BoxHelper( mesh ); + + var sceneCenter = this.objectCenter(mesh); + + var geometry = mesh.geometry; + + var distanceX = (geometry.boundingBox.max.x - geometry.boundingBox.min.x) / 2 / Math.tan(this.camera.fov * this.camera.aspect * Math.PI / 360); + var distanceY = (geometry.boundingBox.max.y - geometry.boundingBox.min.y) / 2 / Math.tan(this.camera.fov * this.camera.aspect * Math.PI / 360); + var distanceZ = (geometry.boundingBox.max.z - geometry.boundingBox.min.z) / 2 / Math.tan(this.camera.fov * Math.PI / 360); + + var maxDistance = Math.max(Math.max(distanceX, distanceY), distanceZ); + maxDistance *= 2.6 * this.scale; + + var cameraPosition = this.camera.position.normalize().multiplyScalar(maxDistance); + + this.controls.maxDistance = 3 * maxDistance; + + this.controls.position0 = cameraPosition; + this.controls.target0 = sceneCenter; + this.controls.reset(); +}; + +ModelViewer.prototype.objectCenter = function (mesh) { + var middle = new THREE.Vector3(); + var geometry = mesh.geometry; + + geometry.center(); + geometry.computeBoundingBox(); + + middle.x = (geometry.boundingBox.max.x + geometry.boundingBox.min.x) / 2; + middle.y = (geometry.boundingBox.max.y + geometry.boundingBox.min.y) / 2; + middle.z = (geometry.boundingBox.max.z + geometry.boundingBox.min.z) / 2; + + mesh.localToWorld(middle); + return middle; +}; + +ModelViewer.prototype.render = function() { + this.renderer.render(this.scene, this.camera); }; \ No newline at end of file