ThreeJS 2D bounding box of 3D object

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

I've tried to Google for an answer but with no success.

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

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

Answers:

Answer

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

Answer

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

Answer

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);
}

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.