@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.
103 lines • 4.21 kB
JavaScript
import { Box3, Vector3 } from "three";
import { CreateWireCube, Gizmos } from "../engine/engine_gizmos.js";
import { getBoundingBox, getWorldPosition, getWorldScale } from "../engine/engine_three_utils.js";
import { getParam } from "../engine/engine_utils.js";
import { Behaviour } from "./Component.js";
const gizmos = getParam("gizmos");
const debug = getParam("debugboxhelper");
/**
* A component that creates a bounding box around an object and provides intersection testing functionality.
*
* Debug mode can be enabled with the URL parameter `?debugboxhelper`, which will visualize intersection tests.
* Helper visualization can be enabled with the URL parameter `?gizmos`.
*
* @category Helpers
* @group Components
*/
export class BoxHelperComponent extends Behaviour {
/** The bounding box for this component */
box = null;
static testBox = new Box3();
_lastMatrixUpdateFrame = -1;
static _position = new Vector3();
static _size = new Vector3(.01, .01, .01);
static _emptyObjectSize = new Vector3(.01, .01, .01);
/**
* Tests if an object intersects with this helper's bounding box
* @param obj The object to test for intersection
* @returns True if objects intersect, false if not, undefined if the provided object is invalid
*/
isInBox(obj) {
if (!obj)
return undefined;
if (!this.box) {
this.box = new Box3();
}
getBoundingBox([obj], undefined, undefined, BoxHelperComponent.testBox);
if (BoxHelperComponent.testBox.isEmpty()) {
const wp = getWorldPosition(obj, BoxHelperComponent._position);
BoxHelperComponent.testBox.setFromCenterAndSize(wp, BoxHelperComponent._emptyObjectSize);
}
this.updateBox();
const intersects = this.box?.intersectsBox(BoxHelperComponent.testBox);
if (intersects) {
if (debug)
Gizmos.DrawWireBox3(BoxHelperComponent.testBox, 0xff0000, 5);
}
return intersects;
}
/**
* Tests if this helper's bounding box intersects with another box
* @param box The {@link Box3} to test for intersection
* @returns True if boxes intersect, false otherwise
*/
intersects(box) {
if (!box)
return false;
return this.updateBox(false).intersectsBox(box);
}
/**
* Updates the helper's bounding box based on the gameObject's position and scale
* @param force Whether to force an update regardless of frame count
* @returns The updated {@link Box3}
*/
updateBox(force = false) {
if (!this.box) {
this.box = new Box3();
}
if (force || this.context.time.frameCount != this._lastMatrixUpdateFrame) {
const firstUpdate = this._lastMatrixUpdateFrame < 0;
this._lastMatrixUpdateFrame = this.context.time.frameCount;
const updateParents = firstUpdate; // updating parents seems to cause falsely calculated positions sometimes?
const wp = getWorldPosition(this.gameObject, BoxHelperComponent._position, updateParents);
const size = getWorldScale(this.gameObject, BoxHelperComponent._size);
this.box.setFromCenterAndSize(wp, size);
}
return this.box;
}
_helper = null;
_color = null;
awake() {
this._helper = null;
this._color = null;
this.box = null;
}
/**
* Creates and displays a visual wireframe representation of this box helper
* @param col Optional color for the wireframe. If not provided, uses default color
* @param force If true, shows the helper even if gizmos are disabled
*/
showHelper(col = null, force = false) {
if (!gizmos && !force)
return;
if (this._helper) {
if (col)
this._color?.set(col);
this.gameObject.add(this._helper);
return;
}
this._helper = CreateWireCube(col);
this.gameObject.add(this._helper);
}
}
//# sourceMappingURL=BoxHelperComponent.js.map