Monday 5 August 2013

Three.js: Importing a Model

This post discusses a small piece of code that uses the three.js library to load a 3D collada scene. Upon starting to write this blog post I thought I’d take a look at some of the problems I’d encountered on the way. To my surprise I realised that I probably had enough information for two posts rather than just one.
This post will look at the exporting of a 3D model from Blender to be used with three.js. I’ll create another post to look at how I then managed to produce a 3D model in Blender and animate it with three.js.
Blender
I had first used Blender several years ago, I even bought one of those ‘For Dummies’ books, but the Blender interface has changed since I last used the software and viewing a video seemed a nice quick way of diving back into it. Therefore I looked at a few Blender tutorials initially to get my head into the application.
After some hours playing around with what I’d seen in the video tutorials I managed to make an extremely crude-looking robot. When I say crude I don’t mean that it featured any phallic appendages! It was simply a very simplistic model.
In order to export my robot model from Blender I used the Export > COLLADA (.dae) option from the Blender File menu. This generated a Collada .dae file for me. At a later point in my experimentation with Blender I attempted to produce a very simplistic animation within Blender and to export this animation. Well this didn’t work terribly well until I installed a script for Blender that allowed me to export my model as a Three.js (.js) file. But more on that in my next post.
One of the first problems that I encountered when initially loading my robot model into the three.js scene was that of weirdly rotated objects. Essentially, objects that I had rotated in Blender in order to create my robot model were appearing non-rotated when imported into my scene. I went so far as to put a question up on the StackOverflow site but then, after investigation, managed to answer my own question. Well, ok I didn’t fix the problem myself but thanks again to the Mr. Doob github area I found the answer. I downloaded the three.js library from the ‘dev’ branch rather than the ‘master’ branch on github and my immediate problems were solved.
In order to be able to export my model from Blender this post came in handy; again on the Mr. Doob github pages. Although this only came into use when I began investigating animation of loaded models.
The Source
Anyway the code is as follows. I’ve based much of this code on my previous examples so some elements, such as my use of require() at the top , may make more sense if you read some of my earlier posts about my experimentation with three.js. I’ve only included the javascript source here.
I think that the code, with its comments, is fairly self explanatory.

require(['libraries/RequestAnimationFrame', 'libraries/Three', 'jquery'], function() {

  var camera, scene, renderer;
  var dae;

  // Create an instance of the collada loader:
  var loader = new THREE.ColladaLoader();

  // Need to convert the axes so that our model does not stand upside-down:
  loader.options.convertUpAxis = true;

  // Load the 3D collada file (robot01.dae in my example), and specify
  // the callback function that is called once the model has loaded:
  loader.load( './models/robot01.dae', function ( collada ) {

    // Grab the collada scene data:
    dae = collada.scene;

    // No skin applied to my model so no need for the following:
    // var skin = collada.skins[ 0 ];

    // Scale-up the model so that we can see it:
    dae.scale.x = dae.scale.y = dae.scale.z = 25.0;

    // Initialise and then animate the 3D scene
    // since we have now successfully loaded the model:
    init();
    animate();
  });

  function init() {

    // Instantiate the 3D scene:
    scene = new THREE.Scene();

    // Instantiate an Orthographic camera this time.
    // The Left/Right/Top/Bottom values seem to be relative to the scene's 0, 0, 0 origin.
    // The best result seems to come if the overall viewable area is divided in 2 and
    // the Left & Bottom values set to negative
    camera = new THREE.OrthographicCamera(
      window.innerWidth / -2,   // Left
      window.innerWidth / 2,    // Right
      window.innerHeight / 2,   // Top
      window.innerHeight / -2,  // Bottom
      -2000,            // Near clipping plane
      1000 );           // Far clipping plane

    // Set the camera position so that it's up top and looking down:
    camera.position.y = 100;

    // Rotate around the x-axis by -45 degrees:
    camera.rotation.x -= 45 * (Math.PI/ 180);

    // Add the camera to the scene:
    scene.add(camera);

    // Add some lights to the scene
    var directionalLight = new THREE.DirectionalLight(0xeeeeee , 1.0);
    directionalLight.position.x = 1;
    directionalLight.position.y = 0;
    directionalLight.position.z = 0;
    scene.add( directionalLight );

    var directionalLight2 = new THREE.DirectionalLight(0xeeeeee, 2.0);
    // A different way to specify the position:
    directionalLight2.position.set(-1, 0, 1);
    scene.add( directionalLight2 );

    // Add the loaded model to the scene:
    scene.add(dae);

    // Instantiate the renderer
    renderer = new THREE.WebGLRenderer();
    // .. and set it's size:
    renderer.setSize(window.innerWidth, window.innerHeight);

    // Place the renderer into the HTML (inside the #container div):
    $('#container').append(renderer.domElement);
  }

  function animate() {
    // Defined in the RequestAnimationFrame.js file, this function
    // means that the animate function is called upon timeout:
    requestAnimationFrame( animate );

    render();
  }

  function render() {
    // *** Update the scene ***
    renderer.render(scene, camera);
  }
});

No comments:

Post a Comment