← TeiaViewer examples
Viewport

Picking in an operator

A viewport operator reading the objects under the pointer, and a raycast of the scene from code (scene.raycaster).

CustomOperator.ts
import {
  type PointerIntersections, SceneObjectFilters, SetObjectsStateCommand, Viewer, ViewportOperator,
} from '@stereograph/teiaviewer';
import { Raycaster, Vector2 } from 'three';

/**
 * An operator: the viewport gives it its pointer events, with the objects under the pointer
 * (raycast at the first read, shared by the handlers asking the same).
 */
class PaintOperator extends ViewportOperator {
  readonly name = 'PaintOperator';

  override onPointerClick(_event: PointerEvent, intersections: PointerIntersections) {
    // The first loaded object under the pointer, the others see-through.
    const hit = intersections.getFirst(SceneObjectFilters.BimMeshFilter);
    if (!hit) {
      return;
    }
    // Undoable.
    void new SetObjectsStateCommand(this._viewport.viewer, [hit.object.uuid], {
      diffuseColor: 0xe0533d,
    }).execute();
  }
}

const viewer = new Viewer();
const { viewport } = viewer;

// The operator takes the pointer, until the default one is given back.
viewport.setOperator(new PaintOperator(viewport));
viewport.resetDefaultOperator();

// Picking without pointer: a ray through the centre of the view, every object it hits, sorted
// as seen (highest layer first, then nearest).
const raycaster = new Raycaster();
raycaster.setFromCamera(new Vector2(0, 0), viewport.camera);
const hits = viewer.scene.raycaster.raycast(raycaster.ray, viewport.camera, {
  onlyFirst: false,
});
for (const { object, point } of hits) {
  console.info(object.uuid, point);
}