11

After downloading 3D models from sketchfab.com and importing them into a Three.js scene, they are most of the times not centered and their size is very big.

Is there a way to automatically center and scale gltf models using a script or a software (working on Linux) or otherwise to do it on-the-fly in Three.js and having the camera to move around the object using OrbitControls.

Liam
  • 27,717
  • 28
  • 128
  • 190
b26
  • 632
  • 1
  • 6
  • 25

4 Answers4

13

Yep. This code takes a node and finds its size and centerpoint, then rescales it so the max extent is 1 and its centered at 0,0,0, and above the ground on the y axis.

    var mroot = yourScene;
    var bbox = new THREE.Box3().setFromObject(mroot);
    var cent = bbox.getCenter(new THREE.Vector3());
    var size = bbox.getSize(new THREE.Vector3());

    //Rescale the object to normalized space
    var maxAxis = Math.max(size.x, size.y, size.z);
    mroot.scale.multiplyScalar(1.0 / maxAxis);
    bbox.setFromObject(mroot);
    bbox.getCenter(cent);
    bbox.getSize(size);
    //Reposition to 0,halfY,0
    mroot.position.copy(cent).multiplyScalar(-1);
    mroot.position.y-= (size.y * 0.5);
manthrax
  • 4,918
  • 1
  • 17
  • 16
  • is yourScene a path to a scene object or an actual object? Can you provide some more context to your solution? – Casivio Mar 25 '21 at 23:52
  • yourScene would be whatever scene/object you want to get the bounds of.. in the case of your GLTF loading example you could do let mroot = gltf.scene. hth! – manthrax Mar 26 '21 at 00:57
7
var loader = new THREE.GLTFLoader();
loader.load( 'models/yourmodel.gltf', 
function ( gltf ) {
    gltf.scene.traverse( function ( child ) {
        if ( child.isMesh ) {
            child.geometry.center(); // center here
        }
    });
    gltf.scene.scale.set(10,10,10) // scale here
    scene.add( gltf.scene );
}, (xhr) => xhr, ( err ) => console.error( e ));

To move around the object use controls.target() https://threejs.org/docs/#examples/controls/OrbitControls.target

corashina
  • 1,757
  • 1
  • 13
  • 21
  • 3
    I'm not sure how this fixes my problem. The object is still offset. And scaling parameter in your proposition is not automatic. – b26 Oct 07 '18 at 09:42
3

I resized in REACT like this!

import React, { useState, useRef, useEffect } from "react";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
const Earth = () => {
const [model, setModel] = useState();
useEffect(() => {
    new GLTFLoader().load("scene.gltf", (model) => {
      model.scene.scale.set(0.03, 0.03, 0.03);
      setModel(model);
    });
  });
  return model ? <primitive object={model.scene} /> : null;
};

Just call <Earth />

Daniel
  • 373
  • 4
  • 10
2

Other proposed solutions did not work well for me. However, I tested the simple approach below on several models to be loaded into my scenes and it works nicely.

const loader = new GLTFLoader();
loader.load("assets/model_path/scene.gltf",
      (gltf) => {
        gltf.scene.scale.multiplyScalar(1 / 100); // adjust scalar factor to match your scene scale
        gltf.scene.position.x = 20; // once rescaled, position the model where needed
        gltf.scene.position.z = -20;

        scene.add(gltf.scene);
        render();
      },
      (err) => {
        console.error(err);
      }
    );
Marc
  • 2,183
  • 2
  • 11
  • 16