Three.js: How to center mesh inside another mesh

Viewed 48

I am playing with three JS and trying to figure out how to center mesh inside another mesh or basically put a mesh inside a plane geometry with equal padding on all sides.

Here's my code

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Child object
var child_material = new THREE.MeshBasicMaterial({
    color: "red",
    opacity: 0.9,
    transparent: true,
    side: THREE.DoubleSide
});
var child_geometry = new THREE.PlaneGeometry(20, 2);
var child_mesh = new THREE.Mesh(child_geometry, child_material);

// Set location of child object
child_mesh.geometry.translate(camera.position.x, camera.position.y, -8);
child_mesh.rotation.set(camera.rotation.x, camera.rotation.y, camera.rotation.z);

// Get box measurement from text geom.
var measure = new THREE.Vector3();
var box = new THREE.Box3().setFromObject(child_mesh);

// Get the size and assign to measure param.
box.getSize(measure);

var width = 0;
var height = measure.y + 2;

if (measure.x > measure.z) {
    width = measure.x * 1.8;
} else {
    width = measure.z * 1.8;
}

// Parent object
var parent_material = new THREE.MeshBasicMaterial({
    color: "white",
    opacity: 0.9,
    transparent: true,
    side: THREE.DoubleSide
});
var parent_geometry = new THREE.PlaneGeometry(width, height);
var parent_mesh = new THREE.Mesh(parent_geometry, parent_material);

// Set location of child object
parent_mesh.geometry.translate(camera.position.x, camera.position.y, -9);
parent_mesh.rotation.set(camera.rotation.x, camera.rotation.y, camera.rotation.z);

//Label group
var labelGroup = new THREE.Group();
labelGroup.add(child_mesh);
labelGroup.add(parent_mesh);
scene.add(labelGroup);

camera.position.z = 5;

function animate() {
    requestAnimationFrame(animate);

    renderer.render(scene, camera);
};

animate();

In this example, for simplicity, I tried to position a inner plane geometry/mesh in the middle of an outer plane geometry/mesh. While my current code currently seems to place it in the center, the left/right padding looks bigger than the top/bottom padding. Ideally I want to set a variable for the padding and should be equal on all sides.

Also, it seems to center it fine when being added on the default camera position/rotation, but on some random camera angles, the inner mesh ends up overlowing outside the outer mesh making it not centered.

Do you have a suggestion on how to improve my current code to center it properly with equal padding regardless of inner mesh size? I hope my question make sense. Any help would be much appreciated. Thank you! :)

1 Answers

You have two issues. First is your objects have a large space between them, which means perspective is going to warp your results since you are not using an orthographic camera. The second, you're scaling the "parent" plane multiplicatively, which means the larger dimension is always going to be scaled further than the smaller one. You just need to add a flat "padding" value to each dimension.

Altered code:

// Child object
const mat = new THREE.MeshBasicMaterial({
    color: "red",
    opacity: 0.9,
    side: THREE.DoubleSide
});
const child_geometry = new THREE.PlaneGeometry(20, 2);
const child_mesh = new THREE.Mesh(child_geometry, mat);

// Set location of child object
child_mesh.geometry.translate(camera.position.x, camera.position.y, -2);
child_mesh.rotation.set(camera.rotation.x, camera.rotation.y, camera.rotation.z);

// Get box measurement from text geom.
var box = new THREE.Box3().setFromObject(child_mesh);

// Get the size and assign to measure param.
const size = box.getSize(new THREE.Vector3());

const padding = 1;
var width = 0;
var height = size.y + padding;

if (size.x > size.z) {
    width = size.x + padding;
} else {
    width = size.z + padding;
}

// Parent object
var parent_material = new THREE.MeshBasicMaterial({
    color: "white",
    opacity: 0.9,
    transparent: true,
    side: THREE.DoubleSide
});
var parent_geometry = new THREE.PlaneGeometry(width, height);
var parent_mesh = new THREE.Mesh(parent_geometry, parent_material);

// Set location of child object
parent_mesh.geometry.translate(camera.position.x, camera.position.y, -2.01);
parent_mesh.rotation.set(camera.rotation.x, camera.rotation.y, camera.rotation.z);

With padding fixed:

enter image description here

With padding and position fixed:

enter image description here

Related