# ThreeJS 2D bounding box of 3D object

I need figure out the area on screen which my 3D object uses.

The function `geometry.computeBoundingBox()` is only returning the 3D bounding box.

How could I convert this to a 2D bounding box?

You simply have to convert all vertices to screen space and make a 2D bounding box from them:

``````function computeScreenSpaceBoundingBox(mesh, camera) {
var vertices = mesh.geometry.vertices;
var vertex = new THREE.Vector3();
var min = new THREE.Vector3(1, 1, 1);
var max = new THREE.Vector3(-1, -1, -1);

for (var i = 0; i < vertices.length; i++) {
var vertexWorldCoord = vertex.copy(vertices[i]).applyMatrix4(mesh.matrixWorld);
var vertexScreenSpace = vertexWorldCoord.project(camera);
min.min(vertexScreenSpace);
max.max(vertexScreenSpace);
}

return new THREE.Box2(min, max);
}
``````

The resulting Box2 is in normalized screen coordinates [-1, 1]. You can get the pixels by multiplying with half of the height and width of your renderer:

``````function normalizedToPixels(coord, renderWidthPixels, renderHeightPixels) {
var halfScreen = new THREE.Vector2(renderWidthPixels/2, renderHeightPixels/2)
return coord.clone().multiply(halfScreen);
}
``````

See a demonstration of it here: http://jsfiddle.net/holgerl/6fy9d54t/

EDIT: Reduced memory usage in inner loop by suggestion from @WestLangley

EDIT2: Fixed a bug discovered by @manthrax

Pointed out a bug... learned something...

A bit late to the party, but here is a version that handles groups, children, and buffered geometry:

``````function computeScreenSpaceBoundingBox(obj, camera) {
var min;
var max;

// Is this an array of objects?
if(Array.isArray(obj)) {
for(var i = 0; i < obj.length; ++i) {
let box2 = computeScreenSpaceBoundingBox(obj[i], camera);
if(min === undefined) {
min = box2.min.clone();
max = box2.max.clone();
} else {
min.min(box2.min);
max.max(box2.max);
}
}
}

// Does this object have geometry?
if(obj.geometry !== undefined) {
var vertices = obj.geometry.vertices;
if(vertices === undefined
&& obj.geometry.attributes !== undefined
&& 'position' in obj.geometry.attributes) {
// Buffered geometry
var vertex = new THREE.Vector3();
var pos = obj.geometry.attributes.position;
for(var i = 0; i < pos.count * pos.itemSize; i += pos.itemSize)
{
vertex.set(pos.array[i], pos.array[i + 1], pos.array[1 + 2]);
var vertexWorldCoord = vertex.applyMatrix4(obj.matrixWorld);
var vertexScreenSpace = vertexWorldCoord.project(camera);
if(min === undefined) {
min = vertexScreenSpace.clone();
max = vertexScreenSpace.clone();
}
min.min(vertexScreenSpace);
max.max(vertexScreenSpace);
}
} else {
// Regular geometry
var vertex = new THREE.Vector3();
for(var i = 0; i < vertices.length; ++i) {
var vertexWorldCoord = vertex.copy(vertices[i]).applyMatrix4(obj.matrixWorld);
var vertexScreenSpace = vertexWorldCoord.project(camera);
if(min === undefined) {
min = vertexScreenSpace.clone();
max = vertexScreenSpace.clone();
}
min.min(vertexScreenSpace);
max.max(vertexScreenSpace);
}
}
}

// Does this object have children?
if(obj.children !== undefined) {
for(var i = 0; i < obj.children.length; ++i) {
let box2 = computeScreenSpaceBoundingBox(obj.children[i], camera);
if(min === undefined) {
min = box2.min.clone();
max = box2.max.clone();
} else {
min.min(box2.min);
max.max(box2.max);
}
}
}

return new THREE.Box2(min, max);
}
``````