WebGL With Three.js – Lesson 6
Today we continue our webgl lessons for those who study it and who wants to enhance his knowledge. In today’s lesson we will look at the load process of ready three-dimensional objects. There are many websites where you can download these models, and moreover, if you have an editor of three-dimensional objects (like 3D Max, Maya, or even Blender), you can create your own models. There are also many file formats of three-dimensional objects, such as obj, collada (dae), obj, mtl, stl, vrml and so on. Most of them can be loaded into your three.js scenes using special loaders. And today we will consider how to load three-dimensional models using a variety of loaders.
OBJ
In order to load object files (.obj), we can use OBJLoader.js. It is rather easy to use this library, before all, we need to attach the library (in the section where we link all other necessary scripts):
<script src="js/three.min.js"></script> <script src="js/OBJLoader.js"></script> <script src="js/THREEx.WindowResize.js"></script> <script src="js/OrbitControls.js"></script> <script src="js/stats.min.js"></script> <script src="js/script1.js"></script>
Now, let’s prepare a general skeleton (of all our demos):
var lesson6 = { scene: null, camera: null, renderer: null, container: null, controls: null, clock: null, stats: null, init: function() { // Initialization // create main scene this.scene = new THREE.Scene(); this.scene.fog = new THREE.FogExp2(0xcce0ff, 0.0003); var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight; // prepare camera var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 1, FAR = 2000; this.camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR); this.scene.add(this.camera); this.camera.position.set(0, 100, 300); this.camera.lookAt(new THREE.Vector3(0,0,0)); // prepare renderer this.renderer = new THREE.WebGLRenderer({ antialias:true }); this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); this.renderer.setClearColor(this.scene.fog.color); this.renderer.shadowMapEnabled = true; this.renderer.shadowMapSoft = true; // prepare container this.container = document.createElement('div'); document.body.appendChild(this.container); this.container.appendChild(this.renderer.domElement); // events THREEx.WindowResize(this.renderer, this.camera); // prepare controls (OrbitControls) this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement); this.controls.target = new THREE.Vector3(0, 0, 0); this.controls.maxDistance = 2000; // prepare clock this.clock = new THREE.Clock(); // prepare stats this.stats = new Stats(); this.stats.domElement.style.position = 'absolute'; this.stats.domElement.style.left = '50px'; this.stats.domElement.style.bottom = '50px'; this.stats.domElement.style.zIndex = 1; this.container.appendChild( this.stats.domElement ); // add spot light var spLight = new THREE.SpotLight(0xffffff, 1.75, 2000, Math.PI / 3); spLight.castShadow = true; spLight.position.set(-100, 300, -50); this.scene.add(spLight); // add simple ground var ground = new THREE.Mesh( new THREE.PlaneGeometry(200, 200, 10, 10), new THREE.MeshLambertMaterial({color:0x999999}) ); ground.receiveShadow = true; ground.position.set(0, 0, 0); ground.rotation.x = -Math.PI / 2; this.scene.add(ground); // load a model this.loadModel(); }, loadModel: function() { ...... } }; // Animate the scene function animate() { requestAnimationFrame(animate); render(); update(); } // Update controls and stats function update() { lesson6.controls.update(lesson6.clock.getDelta()); lesson6.stats.update(); } // Render the scene function render() { if (lesson6.renderer) { lesson6.renderer.render(lesson6.scene, lesson6.camera); } } // Initialize lesson on page load function initializeLesson() { lesson6.init(); animate(); } if (window.addEventListener) window.addEventListener('load', initializeLesson, false); else if (window.attachEvent) window.attachEvent('onload', initializeLesson); else window.onload = initializeLesson;
This code creates the empty scene with camera, rendererm control stats and light. Please pay attention to the empty ‘loadModel’ function – we will put here different codes to load models of different formats. Our first format is ‘obj’. Have a look to the following implementation:
// prepare loader and load the model var oLoader = new THREE.OBJLoader(); oLoader.load('models/chair.obj', function(object, materials) { // var material = new THREE.MeshFaceMaterial(materials); var material2 = new THREE.MeshLambertMaterial({ color: 0xa65e00 }); object.traverse( function(child) { if (child instanceof THREE.Mesh) { // apply custom material child.material = material2; // enable casting shadows child.castShadow = true; child.receiveShadow = true; } }); object.position.x = 0; object.position.y = 0; object.position.z = 0; object.scale.set(1, 1, 1); lesson6.scene.add(object); });
Firstly, we created a new instance of THREE.OBJLoader, and then – we loaded ‘chair.obj’ model file. In order to apply a custom material, we traversed through it’s children and applied the prepared material2 (THREE.MeshLambertMaterial). We also applied casting and receiving shadows. In the end – we set the position of the object and set scale value.
MTL
In short, this is an addition for the previously described OBJ format. Because MTL file is file that describes materials of OBJ file. To load OBJ files with support of MTL, we can use another loader: OBJMTLLoader. In order to use it, don’t forget to include necessary libraries:
<script src="js/MTLLoader.js"></script> <script src="js/OBJMTLLoader.js"></script>
Now add the following code into our ‘loadModel’ function:
// prepare loader and load the model var oLoader = new THREE.OBJMTLLoader(); oLoader.load('models/castle.obj', 'models/castle.mtl', function(object) { object.position.x = -200; object.position.y = 0; object.position.z = 100; object.scale.set(0.1, 0.1, 0.1); lesson6.scene.add(object); });
As you can see, the load function accepts more params – we can point our ‘mtl’ file with materials. This method allows us to load model (obj) with textures!
DAE
Collada files (dae) are also popular among 3d designers. This format supports textures as well. In order to load this format, we can use another loader: ColladaLoader. To use it, don’t forget to include necessary libraries:
<script src="js/ColladaLoader.js"></script>
Now add the following code into our ‘loadModel’ function:
// prepare loader and load the model var oLoader = new THREE.ColladaLoader(); oLoader.load('models/mlc.dae', function(collada) { var object = collada.scene; var skin = collada.skins[0]; object.rotation.x = -Math.PI / 2; object.rotation.z = Math.PI / 2; object.position.x = -50; object.position.y = -100; object.position.z = 0; object.scale.set(0.025, 0.025, 0.025); object.updateMatrix(); lesson6.scene.add(object); });
JSON
This format is natively supported by three.js. It also support custom materials (with textures) that are described in the json file. In order to load this format, we can use another loader: JSONLoader:
// prepare loader and load the model var oLoader = new THREE.JSONLoader(); oLoader.load('models/palm.js', function(geometry, materials) { // get original materials var material = new THREE.MeshFaceMaterial(materials); var mesh = new THREE.Mesh(geometry, material); mesh.position.x = -50; mesh.position.y = -80; mesh.position.z = 0; mesh.scale.set(10, 10, 10); lesson6.scene.add(mesh); });
Conclusion
Next lesson we will continue our overview of various formats and loaders. Stay tuned for new lessons and you are sure to find something new and interesting for yourself.