How to Configure Scene.pick Predicate for All Picking Events?

How to make this Triangle predicate the default behavior of Babylon Scene:

(i.e. always pick through Mesh back faces)?

Hi @Deltakosh, is this currently not possible?

If so, where is the default PickInfo predicate being defined? I could not find it in Babylon source code, would like to override pick prototype method with custom default predicate function.

And possibly make PR for it.

Update: is this where default predicate can be defined?:

Scene.prototype.pick = function (x: number, y: number, predicate?: (mesh: AbstractMesh) => boolean, fastCheck?: boolean, camera?: Nullable<Camera>, trianglePredicate?: TrianglePickingPredicate): Nullable<PickingInfo> {
    if (!PickingInfo) {
        return null;
    }
    var result = this._internalPick(
        (world) => {
            if (!this._tempPickingRay) {
                this._tempPickingRay = Ray.Zero();
            }

            this.createPickingRayToRef(x, y, world, this._tempPickingRay, camera || null);
            return this._tempPickingRay;
        },
        predicate,
        fastCheck,
        false,
        trianglePredicate
    );
    if (result) {
        result.ray = this.createPickingRay(x, y, Matrix.Identity(), camera || null);
    }
    return result;
};

By default there is no triangle predicate. Meaning that all triangles are used.

Which feature would you like to use your custom predicate?

I’d like to set default picking behavior per Scene instance for all scene onPointer<Observables>.

Example:

  • TrianglePredicate: main scene allows picking through Mesh backfaces, so that ceiling is only visible and pickable from below while allowing picking furniture down below (through the ceiling from above).
  • Predicate: pick invisible walls, that have mesh.isVisible = false to toggle back their visibility, instead of using mesh.material.alpha = 0 because that increases draw calls unnecessarily.
  • Predicate + TrianglePredicate: when drag and dropping Mesh to the scene in the second floor edit mode, they should pick 2nd floor ground as the base height, while allow selecting items through the 2nd floor ground to items below on the first floor.

In our app, we have the main scene and many swatch preview scenes in separate canvases, each with different picking behaviors, depending on edit modes.

Currently using this HOC approach:

if (!Scene.prototype.___overridenByThisApp) {
  Scene.prototype.___overridenByThisApp = true

  const _internalPick = Scene.prototype._internalPick
  const _internalPickForMesh = Scene.prototype._internalPickForMesh
  Scene.prototype._internalPick = function () {
    if (arguments[1] == null && this.id) arguments[1] = predicate
    return _internalPick.apply(this, arguments)
  }
  Scene.prototype._internalPickForMesh = function () {
    if (arguments[6] == null) arguments[6] = trianglePredicate
    return _internalPickForMesh.apply(this, arguments)
  }
}

but I saw inside InputManager that it overrode predicate in this._onPointerMove, so not sure if it’s enough

My point was more: what are you using picking for? because you can manually call scene.pick with the arguments you need. So which picking feature do you depend on?

(Btw if this is something generic enough we could think about adding a scene.defaultTrianglePredicate)

1 Like

I’m using picking to:

  • Select Mesh
  • Pick Material
  • Apply Material
  • Draw Marquee Selection (similar to Adobe Illustrator)
  • Draw Polygon
  • Edit custom shapes
  • Many more editing features, similar to Blender (i.e. we are building Blender for people with zero CG skills, like Wix for websites)

Most of them use scene onPointerObservables, including manually calling scene.pick, but mostly rely on observables because the app wraps all Babylon.js features in declarative React components.
Example:

class SelectionTool {
  componentDidMount () {
    this.onPointerTap = scene.onPointerObservable.add(this.onTap, PointerEventTypes.POINTERTAP)
    this.onPointerDown = scene.onPointerObservable.add(this.onClick, PointerEventTypes.POINTERDOWN)
    this.onPointerMove = scene.onPointerObservable.add(this.onMove, PointerEventTypes.POINTERMOVE)
    this.onPointerUp = scene.onPointerObservable.add(this.onRelease, PointerEventTypes.POINTERUP)
  }
  /* Select Mesh */
  onTap = ({event, pickInfo: {pickedMesh, faceId, subMeshId}}) => {...}
}

I was also thinking about public scene.defaultTrianglePredicate and scene.defaultPredicate setters that would be used inside all scene internal picking methods.

Feel free to make a PR for it :slight_smile: it might help others as well

We currently already support:

Yes, but the list is not exhaustive (missing pointerDownTrianglePredicate) and it’s only for observables. And I still need to setup HOC for direct scene.pick, scene.pickWithRay, etc. It gets messy…

What I really need is one default predicate and one trianglePredicate setter for literally ALL pick methods and events to have a consistent behavior.

Yes, this needs a proper PR, will do when I have some spare time, having deadlines to finish the app for the release first.

Hi @ecoin just checking in, was your problem solved? :grinning_face_with_smiling_eyes:

not entirely, but I was happy for now with HOC override.