Skip to content
Advertisement

ThreeJs scale object relative to another object

I’m using threejs to render some models (gltf/glb). All of them are of different sizes, some are big and some are small. Now I want scale all of them to the same size.

if i use mesh.scale() that would scale the object relative to it’s own size. Is there any way to achieve this without manually calculating each model’s scale?

UPDATE:

Here’s my code

function loadModels(points) {
  // loader
  const loader = new GLTFLoader();

  const dl = new DRACOLoader();
  dl.setDecoderPath("/scripts/decoder/");
  loader.setDRACOLoader(dl);

  let lengthRatios;
  const meshes = [];

  for (let i = 0; i < store.length; i++) {
    loader.load(
      store[i].model,
      (gltf) => {
        const mesh = gltf.scene;
        const meshBounds = new THREE.Box3().setFromObject(mesh);

        // Calculate side lengths of model1
        const lengthMeshBounds = {
          x: Math.abs(meshBounds.max.x - meshBounds.min.x),
          y: Math.abs(meshBounds.max.y - meshBounds.min.y),
          z: Math.abs(meshBounds.max.z - meshBounds.min.z),
        };

        if (lengthRatios) {
          lengthRatios = [
            lengthRatios[0] / lengthMeshBounds.x,
            lengthRatios[1] / lengthMeshBounds.y,
            lengthRatios[2] / lengthMeshBounds.z,
          ];
        } else {
          lengthRatios = [
            lengthMeshBounds.x,
            lengthMeshBounds.y,
            lengthMeshBounds.z,
          ];
        }

        meshes.push(mesh);
        if (meshes.length == store.length) {
          addModels();
        }
      },
      (xhr) => {
        console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
      },
      (error) => {
        console.log("An error happened");
      }
    );
  }

  function addModels() {
    // Select smallest ratio in order to contain the models within the scene
    const minRation = Math.min(...lengthRatios);

    for (let i = 0; i < meshes.length; i++) {
      // Use smallest ratio to scale the model
      meshes[i].scale.set(minRation, minRation, minRation);

      // position the model/mesh
      meshes[i].position.set(...points[i]);

      // add it to the scene
      scene.add(meshes[i]);
    }
  }
}

Advertisement

Answer

You should create a bounding box around each model.

//Creating the actual bounding boxes
mesh1Bounds = new THREE.Box3().setFromObject( model1 );
mesh2Bounds = new THREE.Box3().setFromObject( model2 );

// Calculate side lengths of model1
let lengthMesh1Bounds = {
  x: Math.abs(mesh1Bounds.max.x - mesh1Bounds.min.x),
  y: Math.abs(mesh1Bounds.max.y - mesh1Bounds.min.y),
  z: Math.abs(mesh1Bounds.max.z - mesh1Bounds.min.z),
};

// Calculate side lengths of model2
let lengthMesh2Bounds = {
  x: Math.abs(mesh2Bounds.max.x - mesh2Bounds.min.x),
  y: Math.abs(mesh2Bounds.max.y - mesh2Bounds.min.y),
  z: Math.abs(mesh2Bounds.max.z - mesh2Bounds.min.z),
};

// Calculate length ratios
let lengthRatios = [
  (lengthMesh1Bounds.x / lengthMesh2Bounds.x),
  (lengthMesh1Bounds.y / lengthMesh2Bounds.y),
  (lengthMesh1Bounds.z / lengthMesh2Bounds.z),
];

// Select smallest ratio in order to contain the models within the scene
let minRatio = Math.min(...lengthRatios);

// Use smallest ratio to scale the model
model.scale.set(minRatio, minRatio, minRatio);
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement