UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.

96 lines 3.95 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { SkinnedMesh } from "three"; import { RaycastOptions } from "../../engine/engine_physics.js"; import { serializable } from "../../engine/engine_serialization.js"; import { NeedleXRSession } from "../../engine/engine_xr.js"; import { Behaviour } from "../Component.js"; import { EventSystem } from "./EventSystem.js"; /** Derive from this class to create your own custom Raycaster * If you override awake, onEnable or onDisable, be sure to call the base class methods * Implement `performRaycast` to perform your custom raycasting logic */ export class Raycaster extends Behaviour { awake() { EventSystem.createIfNoneExists(this.context); } onEnable() { EventSystem.get(this.context)?.register(this); } onDisable() { EventSystem.get(this.context)?.unregister(this); } } export class ObjectRaycaster extends Raycaster { targets = null; raycastHits = []; ignoreSkinnedMeshes = false; start() { this.targets = [this.gameObject]; } performRaycast(opts = null) { if (!this.targets) return null; opts ??= new RaycastOptions(); opts.targets = this.targets; opts.results = this.raycastHits; opts.useAcceleratedRaycast = true; const orig = opts.testObject; if (this.ignoreSkinnedMeshes) { opts.testObject = obj => { // if we are set to ignore skinned meshes, we return false for them if (obj instanceof SkinnedMesh) { return "continue in children"; } // call the original testObject function if (orig) return orig(obj); // otherwise allow raycasting return true; }; } const hits = this.context.physics.raycast(opts); opts.testObject = orig; return hits; } } __decorate([ serializable() ], ObjectRaycaster.prototype, "ignoreSkinnedMeshes", void 0); export class GraphicRaycaster extends ObjectRaycaster { // eventCamera: Camera | null = null; // ignoreReversedGraphics: boolean = false; // rootRaycaster: GraphicRaycaster | null = null; constructor() { super(); this.ignoreSkinnedMeshes = true; } } export class SpatialGrabRaycaster extends Raycaster { /** * Use to disable SpatialGrabRaycaster globally */ static allow = true; performRaycast(_opts) { // ensure we're in XR, otherwise return if (!NeedleXRSession.active) return null; if (!SpatialGrabRaycaster.allow) return null; if (!_opts?.ray) return null; // TODO this raycast should actually start from gripWorldPosition, not the ray origin, for // cases like transient-pointer on VisionOS where the ray starts at the head and not the hand const rayOrigin = _opts.ray.origin; const radius = 0.015; // TODO if needed, check if the input source is a XR controller or hand // draw gizmo around ray origin // Gizmos.DrawSphere(rayOrigin, radius, 0x00ff0022); return this.context.physics.sphereOverlap(rayOrigin, radius, false, true); } } //# sourceMappingURL=Raycaster.js.map