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.

80 lines 3.45 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 { Box3 } from 'three'; import { HTMLMesh } from 'three/examples/jsm/interactive/HTMLMesh.js'; import { InteractiveGroup } from 'three/examples/jsm/interactive/InteractiveGroup.js'; import { serializable } from '../../engine/engine_serialization.js'; import { getWorldRotation, setWorldRotationXYZ } from '../../engine/engine_three_utils.js'; import { Behaviour } from '../Component.js'; export class SpatialHtml extends Behaviour { id = null; keepAspect = false; _object = null; onEnable() { if (this._object) { this.gameObject.add(this._object); return; } if (!this.id || !this.context.mainCamera) return; const div = document.getElementById(this.id); if (!div) { console.warn("Could not find element with id \"" + this.id + "\""); return; } div.style.display = "block"; div.style.visibility = "hidden"; const group = new InteractiveGroup(); group.listenToPointerEvents(this.context.renderer, this.context.mainCamera); // TODO listen to controller events? this.gameObject.add(group); const mesh = new HTMLMesh(div); group.add(mesh); mesh.visible = false; const mat = mesh.material; mat.transparent = true; // need to wait one frame for it to render to get bounds setTimeout(() => { mesh.visible = true; // align box to get bounding box const rot = getWorldRotation(this.gameObject).clone(); setWorldRotationXYZ(this.gameObject, 0, 0, 0); this.gameObject.updateMatrixWorld(); const aabb = new Box3(); aabb.setFromObject(group); this.setWorldRotation(rot.x, rot.y, rot.z); // apply bounds const width = aabb.max.x - aabb.min.x; const height = aabb.max.y - aabb.min.y; if (this.keepAspect) { const aspect = width / height; if (width > height) { mesh.scale.set(1 / width, 1 / height / aspect, 1); } else { mesh.scale.set(1 / width * aspect, 1 / height, 1); } } else { mesh.scale.set(1 / width, 1 / height, 1); } // TODO: replace with world scale once we have that const factor = this.gameObject.scale; mesh.scale.multiply(factor); }, 1); } onDisable() { this._object?.removeFromParent(); } } __decorate([ serializable() ], SpatialHtml.prototype, "id", void 0); __decorate([ serializable() ], SpatialHtml.prototype, "keepAspect", void 0); //# sourceMappingURL=SpatialHtml.js.map