Wednesday, July 19, 2017

Select, Update and Manipulate an Obj file using threejs

Leave a Comment

I am building a 3D Visualization and Interactive application using threejs.
Following are the key functionalities I want to provide in this application:

In this User should be able to:

  • Rotate and Scale the Obj. -- done
  • Manipulate some certain parts of the Obj like, changing its color, replace that part with another. -- pending

I am following the vast threejs documentation and its list of examples, which really helped me a lot and I am able to achieve a little.

Also I have come across an useful threejs inspector Chrome Ext

This threejs inspector Chrome Ext all in all does everything what I want to achive, but unfortunately I am not able to understand that how does it work and how does it able to select and manipulate the parts of an Obj file.

I am using the following piece of code using threejs for now to just display, rotate and scale the Obj file.

if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); var container, camera, controls, scene, renderer; var mtlObject = {}; init(); animate(); function init() {     camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 1000 );     camera.position.z = 500;     controls = new THREE.TrackballControls( camera );     controls.rotateSpeed = 2.0;     controls.zoomSpeed = 2.0;     controls.panSpeed = 2.0;     controls.noZoom = false;     controls.noPan = false;     controls.staticMoving = true;     controls.dynamicDampingFactor = 0.3;     controls.keys = [ 65, 83, 68 ];     controls.addEventListener( 'change', render );      // world     scene = new THREE.Scene();     var ambient = new THREE.AmbientLight( 0x444444 );     scene.add( ambient );     var directionalLight = new THREE.DirectionalLight( 0xffeedd );     directionalLight.position.set( 0, 0, 1 ).normalize();     scene.add( directionalLight );      // model     var onProgress = function ( xhr ) {         if ( xhr.lengthComputable ) {             var percentComplete = xhr.loaded / xhr.total * 100;             console.log( Math.round(percentComplete, 2) + '% downloaded' );         }      };      var onError = function ( xhr ) { };       //mtl loader      THREE.Loader.Handlers.add( /\.dds$/i, new THREE.DDSLoader() );      var mtlLoader = new THREE.MTLLoader();      mtlLoader.setPath( 'obj/' );      mtlLoader.load( 'bike.mtl', function( materials ) {          materials.preload();          var objLoader = new THREE.OBJLoader();          objLoader.setMaterials( materials );          objLoader.setPath( 'obj/' );          objLoader.load( 'bike.obj', function ( object ) {              object.position.y = - 95;              scene.add( object );          }, onProgress, onError );      });       // lights      var light = new THREE.DirectionalLight( 0xffffff );      light.position.set( 1, 1, 1 );      scene.add( light );      var light = new THREE.DirectionalLight( 0x002288 );      light.position.set( -1, -1, -1 );      scene.add( light );      var light = new THREE.AmbientLight( 0x222222 );      scene.add( light );       // renderer      renderer = new THREE.WebGLRenderer( { antialias: false } );      //renderer.setClearColor( scene.fog.color );      renderer.setPixelRatio( window.devicePixelRatio );      renderer.setSize( window.innerWidth, window.innerHeight );      container = document.getElementById( 'container' );      container.appendChild( renderer.domElement );      //      window.addEventListener( 'resize', onWindowResize, false );      //      render();  }  function onWindowResize() {      camera.aspect = window.innerWidth / window.innerHeight;      camera.updateProjectionMatrix();      renderer.setSize( window.innerWidth, window.innerHeight );      controls.handleResize();      render();  }  function animate() {      requestAnimationFrame( animate );      controls.update();  }  function render() {      renderer.render( scene, camera );  }    

Please if anyone can help me out in this. Thanks in advance and please comment if I am missing anything.

1 Answers

Answers 1

All three.js inspector is doing is parsing the scene, and displaying the various properties of the objects in an interactive UI.

Let's say you have an OBJ file arranged like this:

bike   frame   seat   drive     pedals     frontSprocket     chain     rearSprocket     rearWheel   steering     handlebars     fork     frontWheel 

OBJLoader would create a scene hierarchy like this:

bike // THREE.Group   frame // THREE.Mesh   seat // THREE.Mesh   drive // THREE.Group     pedals // THREE.Mesh     frontSprocket // THREE.Mesh     chain // THREE.Mesh     rearSprocket // THREE.Mesh     rearWheel // THREE.Mesh   steering // THREE.Group     handlebars // THREE.Mesh     fork // THREE.Mesh     frontWheel // THREE.Mesh 

three.js inspector displays this same hierarchy, using the names of the objects. When you click on an object in its tree, it references the object in the scene, and grabs/displays its properties, such as its position, rotation, visible state, etc. When you make a change in the three.js inspector UI, it sets the value on the object in the scene, resulting in the changes you see.

You can do all of this yourself, and you don't even need to be so general about it. Say you want to create a map of object name to the scene object for easier reference (searching the scene is fast enough, but it's recursive). So you could do this:

var nameToObject = {}; scene.traverse(function(node){     // watch out for duplicate empty names!     nameToObject[node.name] = node; }); 

(That doesn't give you the hierarchy, but this is just an example.)

Now you can get and update any object by name:

// enlarge the rear tire nameToObject["rearTire"].scale.addScalar(0.1); 

You can read and set all properties of the object. For example, if MTLLoader created a basic material for the frame, you could do something like this:

// make the frame red nameToObject["frame"].material.color.setRGB(1.0, 0.0, 0.0); 

Or you could outright replace the entire material.

For your example of replacing an object, let's say you already loaded a new Mesh called newRearTire...

// replace the rear tire var drive = nameToObject["drive"]; // the parent of rearTire drive.remove(nameToObject["rearTire"]); drive.add(newRearTire); 

(Of course you would need to re-build your name map at this point.)

These are just very general examples, but should get you started. If you encounter any problems accessing your data, leave a comment and I'll try to clarify.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment