@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.
70 lines (57 loc) • 2.54 kB
text/typescript
import { Object3D } from "three";
import { foreachComponent } from "../../engine/engine_gameobject.js";
import { type IComponent } from "../../engine/engine_types.js";
import { type ICanvasGroup, type IGraphic } from "./Interfaces.js";
import { $shadowDomOwner } from "./Symbols.js";
export class UIRaycastUtils {
/** returns the real object when dealing with shadow UI */
static getObject(obj: Object3D): Object3D {
const shadowOwner = obj[$shadowDomOwner];
if(shadowOwner)
{
if((shadowOwner as IComponent).isComponent === true) obj = (shadowOwner as IComponent).gameObject;
else obj = shadowOwner;
}
return obj;
};
static isInteractable(obj: Object3D, out?: { canvasGroup?: ICanvasGroup, graphic?: IGraphic }): boolean {
// reset state
if (out) {
out.canvasGroup = undefined;
out.graphic = undefined;
}
if (obj === null || obj === undefined || !obj.visible) return false;
obj = this.getObject(obj);
if(!obj.visible) return false;
const canvasGroup = this.tryFindCanvasGroup(obj);
if (canvasGroup?.isCanvasGroup === true) {
if (out) out.canvasGroup = canvasGroup as ICanvasGroup;
if (canvasGroup.blocksRaycasts === false) return false;
if (canvasGroup.interactable === false) return false;
}
// handle Graphic Raycast target
const graphic : IGraphic | undefined = foreachComponent(obj, c => {
if ((c as unknown as IGraphic).isGraphic === true) return c;
return undefined;
}, false);
// console.log(obj, graphic?.raycastTarget);
if (out) {
if (graphic?.isGraphic === true)
out.graphic = graphic as IGraphic;
}
if (graphic?.raycastTarget === false) return false;
if (graphic?.layer === 2) return false;
return true;
}
private static tryFindCanvasGroup(obj: Object3D | null): ICanvasGroup | null {
if (!obj) return null;
// test for canvas groups
const res = foreachComponent(obj, c => {
const gr = c as unknown as ICanvasGroup;
if (gr.blocksRaycasts !== undefined && gr.interactable !== undefined) return gr;
return undefined;
}, false);
if (res !== undefined) return res;
return this.tryFindCanvasGroup(obj.parent);
}
}