UNPKG

awv3

Version:
125 lines (109 loc) 4.76 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 = 0.1; this._inverseMatrix = new THREE.Matrix4(); this._ray = new THREE.Ray(); this._sphere = new THREE.Sphere(); this._vA = new THREE.Vector3(); this._vB = new THREE.Vector3(); this._vC = new THREE.Vector3(); this._tempA = new THREE.Vector3(); this._tempB = new THREE.Vector3(); this._tempC = new THREE.Vector3(); this._uvA = new THREE.Vector2(); this._uvB = new THREE.Vector2(); this._uvC = new THREE.Vector2(); this._barycoord = new THREE.Vector3(); this._intersectionPoint = new THREE.Vector3(); this._intersectionPointWorld = new THREE.Vector3(); } 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); } } intersects.sort( (a, b) => b.receiver.interaction.priority - a.receiver.interaction.priority || 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', };