Detecting clicks on an imported asset

Hey there,

I’m trying to detect pointer-down events on imported assets, but struggling to find the correct way to do so.
Similar to an RTS game, I want the player to be able to “select” buildings and units on a plane.

The click hit box doesn’t have to exactly match the shown asset, just a rough circle or square around it is more than enough.

I’ve tried following this doc about creating a bounding box around an array of meshes (Drawing Bounding Boxes | Babylon.js Documentation) and am now lost about detecting clicks on it, or even if this is right way to start.

So I’ve got a few questions:

Is creating a parent mesh the way to go ?

Is creating a bounding box helpful ?

What’s the recommended way to import my assets (They will be loaded into the scene multiple times each) ?

  • SceneLoader.ImportMesh ?
  • AssetContainer ?
  • AssetManager ?

Here’s what I tried so far, which only creates a parent bounding box and mesh that isn’t pickable :
meshes is the array of meshes given by SceneLoader.ImportMesh

It might be the wrong way to think about this problem, I’m open to other solutions

  let min = null;
  let max = null;

  const parent = new Mesh(name, scene);

  for (const mesh of meshes) {
    mesh.setParent(parent);
    mesh.isPickable = false; // I only want the parent element to be selectable

    const meshMin = mesh.getBoundingInfo().boundingBox.minimumWorld;
    const meshMax = mesh.getBoundingInfo().boundingBox.maximumWorld;

    min = min ? Vector3.Minimize(min, meshMin) : meshMin;
    max = max ? Vector3.Maximize(max, meshMax) : meshMax;
  }

  if (!min || !max) throw "Couldn't compute bounding box";

  parent.setBoundingInfo(new BoundingInfo(min, max));
  parent.scaling.scaleInPlace(1.1); //Makes the asset easier to select

  parent.isPickable = true; // Doesn't work, my mesh does not contain any vertices

cc @Cedric for the best technique but I would usually add invisible meshes to handle the clicks :slight_smile:

Adding an invisible child sphere mesh does the trick.

Although it creates another mesh below the parent one that’s supposed to represent the same thing, my main concern is about good practices on this solution

  const boundingInfo = new BoundingInfo(min, max);
  boundingInfo.boundingSphere.center;

  const sphere = MeshBuilder.CreateSphere(id, {
    diameter: boundingInfo.diagonalLength,
  });
  sphere.position = Vector3.Center(min, max);
  sphere.position.y = 0;

  const invisible= new StandardMaterial("invisible", scene);
  invisible.alpha = 0;
  sphere.material = invisible;

  parent.setBoundingInfo(boundingInfo);

  sphere.setParent(parent);
1 Like

Yes, I would also do it with invisible mesh so it’s easy to tweak its shape.

Check this PG

2 Likes