3

All I want to do is load an OBJ file and translate its coordinates to the world origins (0,0,0) so that orbit controls work perfectly (no Pivot points please).

I'd like to load random OBJ objects with different geometries/center points and have them translated automatically to the scene origin. In other words, a 'hard coded' translate solution for a specific model won't work

This has got to be one of the most common scenarios for Three JS (basic 3d object viewer), so I'm surprised I can't find a definitive solution on SO.

Unfortunately there are a lot of older answers with deprecated functions, so I would really appreciate a new answer even if there are similar solutions out there.

Things I've tried

  1. the code below fits the object nicely to the camera, but doesn't solve the translation/orbiting problem.

    // fit camera to object
    var bBox = new THREE.Box3().setFromObject(scene);
    var height = bBox.size().y;
    var dist = height / (2 * Math.tan(camera.fov * Math.PI / 360));
    var pos = scene.position;
    
    // fudge factor so the object doesn't take up the whole view
    camera.position.set(pos.x, pos.y, dist * 0.5); 
    camera.lookAt(pos);
    
  2. Apparently the geometry.center() is good for translating an object's coordinates back to the origin, but the THREE.GeometryUtils.center has been replaced by geometry.center() and I keep getting errors when trying to use it.

  3. when loading OBJs, geometry has now been replaced by bufferGeometry. I can't seem to cast the buffergeometry into geometry in order to use the center() function. do I have to place this in the object traverse > child loop like so? this seems unnecessarily complicated.

    geometry = new THREE.Geometry().fromBufferGeometry( child.geometry );
    

My code is just a very simple OBJLoader.

      var objLoader = new THREE.OBJLoader();
      objLoader.setPath('assets/');
      objLoader.load('BasketballNet_Skull.obj', function (object) {


            object.traverse( function ( child ) {

                if ( child instanceof THREE.Mesh ) {

                   child.material = material;

                }

        } );
       scene.add(object);
});

(BTW first real question on SO so forgive any formatting / noob issues)

Maxime Pacary
  • 22,336
  • 11
  • 85
  • 113
lukemunn
  • 51
  • 1
  • 6
  • Hello! Don't forget to mark the correct answer as such. If your question remains unanswered you may add information about what you need (click edit). – Samie Bencherif Apr 26 '19 at 19:37

3 Answers3

2

Why not object.geometry.center()?

var objLoader = new THREE.OBJLoader();
      objLoader.setPath('assets/');
      objLoader.load('BasketballNet_Skull.obj', function (object) {


            object.traverse( function ( child ) {

                if ( child instanceof THREE.Mesh ) {

                   child.material = material;
                   child.geometry.center();

                }

        } );
       scene.add(object);
Samie Bencherif
  • 1,285
  • 12
  • 27
1

OK figured this out, using some very useful functions from Meshviewer Master, an older Three JS object viewer. https://github.com/ideesculture/meshviewer All credit to Gautier Michelin for this code https://github.com/gautiermichelin

After loading the OBJ, you need to do 3 things:

1. Create a Bounding Box based on the OBJ

    boundingbox = new THREE.BoundingBoxHelper(object, 0xff0000);

    boundingbox.update();

    sceneRadiusForCamera = Math.max(
        boundingbox.box.max.y - boundingbox.box.min.y,
        boundingbox.box.max.z - boundingbox.box.min.z,
        boundingbox.box.max.x - boundingbox.box.min.x
    )/2 * (1 + Math.sqrt(5)) ; // golden number to beautify display

2. Setup the Camera based on this bounding box / scene radius

function showFront() {
if (objectCopy !== undefined) objectCopy.rotation.z =  0;
    controls.reset();
    camera.position.z = 0;
    camera.position.y = 0;
    camera.position.x = sceneRadiusForCamera;
    camera.lookAt(scene.position);
}

(the mesh viewer code also contains functions for viewing left, top, etc)

3. Reposition the OBJ to the scene origin Like any centering exercise, the position is then the width and height divided by 2

function resetObjectPosition(){
    boundingbox.update();

    size.x = boundingbox.box.max.x - boundingbox.box.min.x;
    size.y = boundingbox.box.max.y - boundingbox.box.min.y;
    size.z = boundingbox.box.max.z - boundingbox.box.min.z;

    // Repositioning object
    objectCopy.position.x = -boundingbox.box.min.x - size.x/2;
    objectCopy.position.y = -boundingbox.box.min.y - size.y/2;
    objectCopy.position.z = -boundingbox.box.min.z - size.z/2;
    boundingbox.update();
    if (objectCopy !== undefined) objectCopy.rotation.z =  0;

} 
lukemunn
  • 51
  • 1
  • 6
0

From my understanding of your question, you want the objects that are added to the scene in the origin of the camera view. I believe the common way of achieving an object viewer solution is adding camera controls to your camera in the scene mostly THREE.OrbitControls and specifying the target for the camera as the object that you want to focus on. This makes the object focused to be in the center and the camera rotation and movement will be based on that object.

NikhilSN
  • 43
  • 1
  • 13
  • Thanks for reply NikhilSN but not really what I'm looking for, maybe question was too long / vague. Basically problem is - given any loaded OBJ how do you translate its coordinates to the center so that camera and orbitcontrols 'just work' . – lukemunn Dec 08 '16 at 21:01