Get mesh bounding box position and size in 2d screen coordinates

Hi!

I’m doing a mashup where I have a BJS scene and now I want to overlay a popper.js tooltip when I hover over some meshes.

for popper.js to be able to know where to position itself you need to pass in a referenceObject.

import { ReferenceObject } from 'popper.js'
 
const ref: ReferenceObject = {
        clientHeight: 1000, // screen width
        clientWidth: 500, // screen height
        getBoundingClientRect() {
          return {
            width: 400, // the meshes boundingbox width
            height: 300, // the meshes boundingbox height
            left: 200, // how far from the left is the boundingbox
            top: 100,
            right: 400,
            bottom: 100,
          }
        },
      }

I’ve done some reading and found this example, which i don’t fully understand:

const mesh: Mesh // the mesh I want to know the size and position of
const worldMatrix = mesh.getWorldMatrix()
const transformMatrix = scene.getTransformMatrix()
const position = mesh.position
const viewport = scene.activeCamera!.viewport
const coordinates = Vector3.Project(position, worldMatrix, transformMatrix, viewport)

And now I’m stuck, because I don’t understand how I should get the boundingbox for the mesh in 2d.

Has anyone got some insight? :slight_smile:

You could project all the corners of the mesh bounding box and then keep the both with respectively minX minY and maxX maxY so that it would define a rectangle top left and bottom right coordinate on screen.

Here’s my finished function, maybe it will help someone else :slight_smile:

private getClientRectFromMesh(mesh: Mesh): ClientRect {

    // get bounding box of the mesh
    const meshVectors = mesh.getBoundingInfo().boundingBox.vectors

    // get the matrix and viewport needed to project the vectors onto the screen
    const worldMatrix = mesh.getWorldMatrix()
    const transformMatrix = this.scene.getTransformMatrix()
    const viewport = this.scene.activeCamera!.viewport

    // loop though all the vectors and project them against the current camera viewport to get a set of coordinates
    const coordinates = meshVectors.map(v => {
      const proj = Vector3.Project(v, worldMatrix, transformMatrix, viewport)
      proj.x = proj.x * canvas.clientWidth
      proj.y = proj.y * canvas.clientHeight
      return proj
    })

    // get the min and max for all the coordinates so we can calculate the largest possible screen size
    // using d3.extent
    const [minX, maxX] = extent(coordinates, c => c.x) as number[]
    const [minY, maxY] = extent(coordinates, c => c.y) as number[]

    // return a ClientRect from this
    const rect: ClientRect = {
      width: maxX - minX,
      height: maxY - minY,
      left: minX,
      top: minY,
      right: maxX,
      bottom: maxY,
    }

    // console.timeEnd('rectfrommesh') // on average 0.05ms

    return rect
  }
6 Likes