Table of Contents#
- Prerequisites
- Setting Up the Three.js Scene
- Importing GLTF Models
- Calculating Model Bounds with Bounding Boxes
- Automatically Centering the Model
- Resizing the Model to Fit the View
- Integrating with OrbitControls
- Full Example Code
- Troubleshooting Common Issues
- Conclusion
- References
Prerequisites#
Before diving in, ensure you have:
- Basic knowledge of JavaScript and Three.js (familiarity with
Scene,Camera,Renderer, andMesh). - A development environment (e.g., VS Code with Live Server).
- The following Three.js libraries (we’ll use CDNs for simplicity):
- Three.js core (
three.min.js). GLTFLoader(to import GLTF models).OrbitControls(for interactive camera controls).
- Three.js core (
Setting Up the Three.js Scene#
First, let’s create a basic Three.js scene. This includes a scene, camera, renderer, and lights (critical for visibility).
Step 1: HTML Structure#
Create an HTML file with a canvas element (where the 3D scene will render) and include the required Three.js libraries via CDN:
<!DOCTYPE html>
<html>
<head>
<title>Auto-Center & Resize GLTF Model</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/loaders/GLTFLoader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/controls/OrbitControls.js"></script>
<script>
// Three.js code will go here
</script>
</body>
</html>Step 2: Initialize Scene, Camera, and Renderer#
In the <script> tag, set up the core Three.js components:
// Scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f0f0); // Light gray background
// Camera (PerspectiveCamera: fov, aspect ratio, near, far)
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Lights (required to see the model!)
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // Soft white light
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(5, 5, 5); // Position light above/behind the camera
scene.add(directionalLight);Step 3: Handle Window Resizing#
Add a listener to adjust the camera and renderer when the window resizes:
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});Importing GLTF Models#
Next, we’ll import a GLTF model using GLTFLoader. For this tutorial, use a sample GLTF model (e.g., from Khronos Group’s GLTF Sample Models).
Step 1: Load the Model#
Use GLTFLoader to import the model. Add error handling for failed loads:
const loader = new THREE.GLTFLoader();
// Load a GLTF model (replace with your model's path)
loader.load(
'models/Duck.glb', // Sample model (Duck.glb)
(gltf) => {
// Called when the model loads successfully
const model = gltf.scene;
scene.add(model); // Add model to the scene
// We'll process centering/resizing here later!
},
(xhr) => {
// Optional: Progress callback
console.log((xhr.loaded / xhr.total * 100) + '% loaded');
},
(error) => {
// Error callback
console.error('An error occurred loading the model:', error);
}
);At this point, the model will load but may be off-center or incorrectly sized. Let’s fix that!
Calculating Model Bounds with Bounding Boxes#
To center and resize the model, we first need to find its bounding box—a 3D box that encloses all vertices of the model. Three.js provides Box3 for this.
What is a Bounding Box?#
A Box3 (axis-aligned bounding box) defines the minimum and maximum coordinates (min and max) of a 3D object. For example, a cube from (1,1,1) to (3,3,3) has min = (1,1,1) and max = (3,3,3).
Step 1: Compute the Bounding Box for the GLTF Model#
GLTF models often have nested objects (e.g., meshes, bones). Use Box3.setFromObject() to automatically traverse all objects in the model and compute the overall bounding box:
// Inside the GLTFLoader success callback:
const model = gltf.scene;
scene.add(model);
// Compute bounding box
const boundingBox = new THREE.Box3().setFromObject(model);setFromObject(model) traverses all child objects of model and calculates the smallest box that contains them all.
Automatically Centering the Model#
Now that we have the bounding box, we can find the model’s center and reposition it to the origin (0,0,0).
Step 1: Find the Model’s Center#
Use boundingBox.getCenter() to get the 3D coordinates of the model’s current center:
const center = new THREE.Vector3();
boundingBox.getCenter(center); // center now holds (x, y, z) of the model's centerStep 2: Translate the Model to the Origin#
To center the model, move it so its center aligns with (0,0,0). Subtract the center coordinates from the model’s position:
model.position.sub(center); // Moves model so its center is at (0,0,0)Why? If the model’s center is (2, 3, 4), model.position.sub(center) sets model.position to (-2, -3, -4), shifting the model so its center is at (0,0,0).
Resizing the Model to Fit the View#
Even if centered, the model might be too large (clipping the camera) or too small (hard to see). We’ll scale it to fit within the camera’s view.
Step 1: Calculate the Model’s Size#
Use boundingBox.getSize() to get the model’s dimensions (width, height, depth):
const size = new THREE.Vector3();
boundingBox.getSize(size); // size = { x: width, y: height, z: depth }Step 2: Determine the Maximum Dimension#
To ensure the model fits, use the largest dimension (width, height, or depth):
const maxDim = Math.max(size.x, size.y, size.z); // Largest dimension of the modelStep 3: Compute the Scale Factor#
We want the model to fit within a "target size" (e.g., 5 units). The scale factor is targetSize / maxDim:
const targetSize = 5; // Adjust this to control how large the model appears
const scaleFactor = targetSize / maxDim;
model.scale.set(scaleFactor, scaleFactor, scaleFactor); // Uniform scalingStep 4: Reposition the Camera#
After scaling, adjust the camera’s position to ensure the entire model is visible. Use the scaled size to set the camera’s distance from the origin:
// Position camera along the z-axis, far enough to see the scaled model
camera.position.z = maxDim * scaleFactor * 2; // Adjust multiplier (e.g., 2) for comfortIntegrating with OrbitControls#
OrbitControls lets users pan, zoom, and rotate the camera around a target point. To ensure controls work with our centered model, set the target to the model’s center (origin, (0,0,0)).
Step 1: Initialize OrbitControls#
Add OrbitControls to the scene:
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // Smooth camera movement
controls.dampingFactor = 0.05;Step 2: Set Controls Target#
By default, OrbitControls orbits around (0,0,0) (our model’s new center). Confirm this with:
controls.target.set(0, 0, 0); // Orbit around the origin (model's center)
controls.update(); // Apply changesNow, dragging the mouse will orbit around the model’s center!
Full Example Code#
Here’s the complete code, combining all steps:
<!DOCTYPE html>
<html>
<head>
<title>Auto-Center & Resize GLTF Model</title>
<style>
body { margin: 0; }
canvas { display: block; }
</style>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/loaders/GLTFLoader.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/controls/OrbitControls.js"></script>
<script>
// Scene
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xf0f0f0);
// Camera
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// Renderer
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// Lights
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(5, 5, 5);
scene.add(directionalLight);
// OrbitControls
const controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.target.set(0, 0, 0); // Orbit around origin
// Load GLTF Model
const loader = new THREE.GLTFLoader();
loader.load(
'models/Duck.glb', // Replace with your model path
(gltf) => {
const model = gltf.scene;
scene.add(model);
// Step 1: Compute bounding box
const boundingBox = new THREE.Box3().setFromObject(model);
// Step 2: Center the model
const center = new THREE.Vector3();
boundingBox.getCenter(center);
model.position.sub(center);
// Step 3: Resize the model
const size = new THREE.Vector3();
boundingBox.getSize(size);
const maxDim = Math.max(size.x, size.y, size.z);
const targetSize = 5; // Adjust based on desired size
const scaleFactor = targetSize / maxDim;
model.scale.set(scaleFactor, scaleFactor, scaleFactor);
// Step 4: Position camera to see the model
camera.position.z = maxDim * scaleFactor * 2; // Distance from model
},
(xhr) => console.log((xhr.loaded / xhr.total * 100) + '% loaded'),
(error) => console.error('Model load error:', error)
);
// Window resize handler
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Animation loop
function animate() {
requestAnimationFrame(animate);
controls.update(); // Required for damping
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>Troubleshooting Common Issues#
1. Model is Invisible#
- Lights: Ensure
AmbientLightandDirectionalLightare added to the scene (models are black without light). - Camera Position: If the camera is inside the model, adjust
camera.position.zto be larger.
2. Bounding Box is Empty#
- Nested Objects:
setFromObject()may fail if the model has zero-scale objects. Verify the model’s geometry in a tool like Blender. - Model Not Loaded: Ensure the model path is correct (use absolute paths if needed).
3. OrbitControls Not Working#
- Target: Confirm
controls.targetis set to(0,0,0)(the model’s center). - Renderer DOM Element: Pass
renderer.domElementtoOrbitControls(required for mouse input).
Conclusion#
You now know how to automatically center and resize GLTF models in Three.js! By computing the bounding box, translating the model to the origin, scaling it to fit the view, and integrating OrbitControls, you can ensure any imported model looks polished and interactive.
This workflow is critical for dynamic applications (e.g., user-uploaded models) where manual adjustments aren’t feasible. Experiment with targetSize and camera position to fine-tune results!