UNPKG

awv3

Version:
115 lines (99 loc) 4.46 kB
import * as THREE from 'three'; export default class Raycaster extends THREE.Raycaster { constructor(interaction, options = { approach: Raycaster.Approach.FirstMatch }) { super(); this.interaction = interaction; this.view = interaction.view; this.linePrecision = 1.5; } isActuallyVisible(obj) { while (obj) { if (obj.visible === false) return false; if (obj.material && obj.material.visible === false) return false; obj = obj.parent; } return true; } castObjects(objects, intersects = [], filter = undefined) { for (let i = 0, l = objects.length, object; i < l; i++) { object = objects[i]; if ( // No filter, filter is empty, or object is part of filter (!filter || filter.length === 0 || filter.indexOf(object) >= 0) && // must be interactive object.interactive && // must have interaction object.interaction && // must be enabled object.interaction.enabled && // muste be activ (have interaction related listeners) object.interaction._active && // must be visible this.isActuallyVisible(object) ) { // ... then we intersect this.intersect(object, object.interaction.recursive, intersects, object.interaction.types, object); } } // Sort items after priority. The receiver has it, and each object can define one as well on the prototype. // If no priority has been given or if it yields 0, the distance will be used to determine the hits importance intersects.sort( (a, b) => (b.receiver.interaction.priority || 0) + b.object.interactionPriority - ((a.receiver.interaction.priority || 0) + a.object.interactionPriority) || a.distance - b.distance, ); return intersects; } intersect(object, recursive, intersects, types, parent) { let op = true; // Inspect types if (!!types) { if (Array.isArray(types)) { op = !(object.type !== 'Object3D' && object.type !== 'Group' && types.indexOf(object.type) == -1); } else if (typeof types === 'function') op = types(object); } // false op stops operation right here, undefined op at least proceeds with childs if (op == false) return; let count = intersects.length; // true op allows raycast if (op == true) object.raycast(this, intersects, parent.interaction.approach); if (intersects.length != count) { for (let i = count, intersect, l = intersects.length; i < l; i++) { intersect = intersects[i]; intersect.receiver = parent; // If the parent/receiver is not recursive data.object should point back to it if (!parent.interaction.recursive) { intersect.receiver.object = parent; } } } // If the root is not recursive there's no point in iterating further if (!parent.interaction.recursive) return; for (let i = 0, l = object.children.length, child, isMultiMaterial; i < l; i++) { child = object.children[i]; isMultiMaterial = Array.isArray(child.material); // To proceed, a child: if ( // is visible child.visible && // is interactive child.interactive && // doesn't have a material (!child.material || // OR has a single material and it is visible (!isMultiMaterial && child.material.visible === true) || // OR has many materials and the first is visible // TODO: is this really what we want? seems kind of random (isMultiMaterial && child.material[0].visible === true)) ) { this.intersect(child, true, intersects, types, parent); } } } } // TODO: Deprecate approaches // Do we really need to fork each objects raycast if it perhaps only brings a small benefit anyway? Raycaster.Approach = { Default: 'Default', };