UNPKG

@webarkit/arnft-threejs

Version:

The ARnft rendering engine, based on Three.js

256 lines (244 loc) 10.4 kB
import { Object3D, PlaneGeometry, Scene, TextureLoader, VideoTexture, Mesh, MeshStandardMaterial } from "three"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { Utils } from "../utils/Utils"; import SceneRendererTJS from "../SceneRendererTJS"; /** * Interface to define the ARVideo object used in addVideo. * @param play play a video. */ interface ARvideo { play: () => void; } /** * Interface to define an Entity. * @param name the name of the Entity */ interface Entity { name: string; } /** * Interface to define the PlaneGeometry used in the addImage and addVideo functions. * @param w width of the PlaneGeometry. * @param h height of the PlaneGeometry. * @param ws width number of segments of the PlaneGeometry. * @param hs height number of segments of the PlaneGeometry. */ interface IPlaneConfig { w: number; h: number; ws: number; hs: number; } /** * This class is responsable to attach Threejs object to the rendering root and pass matrix data to it. */ export default class NFTaddTJS { private entities: Entity[] = []; private names: Array<string>; private scene: Scene; private target: EventTarget; private uuid: string; /** * The NFTaddTJS constuctor, you need to pass the uuid from the ARnft instance. * @param uuid the uuid. */ constructor(uuid: string) { this.scene = SceneRendererTJS.getGlobalScene(); this.target = window || global; this.uuid = uuid; this.names = []; } /** * The add function will add a mesh to the Renderer root. You need to associate a name of the Entity. * @param mesh The mesh to add * @param name the name of the Entity associated. * @param objVisibility set true or false if the mesh wll stay visible or not after tracking. */ public add(mesh: Object3D, name: string, objVisibility: boolean) { this.target.addEventListener("getNFTData-" + this.uuid + "-" + name, (ev: any) => { var msg = ev.detail; mesh.position.y = ((msg.height / msg.dpi) * 2.54 * 10) / 2.0; mesh.position.x = ((msg.width / msg.dpi) * 2.54 * 10) / 2.0; }); const root = new Object3D(); root.name = "root-" + name; this.scene.add(root); root.add(mesh); this.target.addEventListener("getMatrixGL_RH-" + this.uuid + "-" + name, (ev: any) => { root.visible = true; mesh.visible = true; root.matrixAutoUpdate = false; Utils.setMatrix(root.matrix, ev.detail.matrixGL_RH); }); this.target.addEventListener("nftTrackingLost-" + this.uuid + "-" + name, (ev: any) => { root.visible = objVisibility; mesh.visible = objVisibility; }); this.names.push(name); this.entities.push({ name }); } /** * The addModel function will add a model to the Renderer root. You need to associate a name of the Entity. * @param url url of the model. * @param name the name of the Entity associated. * @param scale scale of the model. * @param objVisibility set true or false if the mesh wll stay visible or not after tracking. */ public addModel(url: string, name: string, scale: number, objVisibility: boolean) { const root = new Object3D(); root.name = "root-" + name; this.scene.add(root); let model: any; /* Load Model */ const threeGLTFLoader = new GLTFLoader(); threeGLTFLoader.load(url, (gltf: { scene: Object3D }) => { model = gltf.scene; model.scale.set(scale, scale, scale); model.rotation.x = Math.PI / 2; this.target.addEventListener("getNFTData-" + this.uuid + "-" + name, (ev: any) => { var msg = ev.detail; model.position.y = ((msg.height / msg.dpi) * 2.54 * 10) / 2.0; model.position.x = ((msg.width / msg.dpi) * 2.54 * 10) / 2.0; }); root.add(model); }); this.target.addEventListener("getMatrixGL_RH-" + this.uuid + "-" + name, (ev: any) => { root.visible = true; model.visible = true; root.matrixAutoUpdate = false; Utils.setMatrix(root.matrix, ev.detail.matrixGL_RH); }); this.target.addEventListener("nftTrackingLost-" + this.uuid + "-" + name, (ev: any) => { root.visible = objVisibility; model.visible = objVisibility; }); this.names.push(name); } /** * The addModelWithCallback function will add a model to the Renderer root. You need to associate a name of the Entity. * You can modify the model rotation, scale and other properties with the callback. * @param url url of the model. * @param name the name of the Entity associated. * @param callback modify the model in the callback. * @param objVisibility set true or false if the mesh wll stay visible or not after tracking. */ public addModelWithCallback(url: string, name: string, callback: (gltf: any) => {}, objVisibility: boolean) { const root = new Object3D(); root.name = "root-" + name; this.scene.add(root); let model: any; /* Load Model */ const threeGLTFLoader = new GLTFLoader(); threeGLTFLoader.load(url, (gltf: { scene: Object3D }) => { model = gltf.scene; this.target.addEventListener("getNFTData-" + this.uuid + "-" + name, (ev: any) => { var msg = ev.detail; model.position.y = ((msg.height / msg.dpi) * 2.54 * 10) / 2.0; model.position.x = ((msg.width / msg.dpi) * 2.54 * 10) / 2.0; }); callback(gltf); root.add(model); }); this.target.addEventListener("getMatrixGL_RH-" + this.uuid + "-" + name, (ev: any) => { root.visible = true; model.visible = true; root.matrixAutoUpdate = false; Utils.setMatrix(root.matrix, ev.detail.matrixGL_RH); }); this.target.addEventListener("nftTrackingLost-" + this.uuid + "-" + name, (ev: any) => { root.visible = objVisibility; model.visible = objVisibility; }); this.names.push(name); } /** * The addImage function will add an image to the Renderer root. You need to associate a name of the Entity. * @param imageUrl url of the image. * @param name the name of the Entity associated. * @param color color of the background plane. * @param scale scale of the plane. * @param configs see IPlaneConfig. * @param objVisibility set true or false if the mesh wll stay visible or not after tracking. */ public addImage( imageUrl: string, name: string, color: string, scale: number, configs: IPlaneConfig, objVisibility: boolean ) { const root = new Object3D(); root.name = "root-" + name; this.scene.add(root); const planeGeom = new PlaneGeometry(configs.w, configs.h, configs.ws, configs.hs); const texture = new TextureLoader().load(imageUrl); const material = new MeshStandardMaterial({ color: color, map: texture }); const plane = new Mesh(planeGeom, material); plane.scale.set(scale, scale, scale); this.target.addEventListener("getNFTData-" + this.uuid + "-" + name, (ev: any) => { var msg = ev.detail; plane.position.y = ((msg.height / msg.dpi) * 2.54 * 10) / 2.0; plane.position.x = ((msg.width / msg.dpi) * 2.54 * 10) / 2.0; }); root.add(plane); this.target.addEventListener("getMatrixGL_RH-" + this.uuid + "-" + name, (ev: any) => { root.visible = true; plane.visible = true; root.matrixAutoUpdate = false; Utils.setMatrix(root.matrix, ev.detail.matrixGL_RH); }); this.target.addEventListener("nftTrackingLost-" + this.uuid + "-" + name, (ev: any) => { root.visible = objVisibility; plane.visible = objVisibility; }); this.names.push(name); } /** * The addVideo function will add a video to the Renderer root. You need to associate a name of the Entity. * @param id the id of the html video element. * @param name the name of the Entity associated. * @param scale scale of the plane. * @param configs see IPlaneConfig. * @param objVisibility set true or false if the mesh wll stay visible or not after tracking. */ public addVideo(id: string, name: string, scale: number, configs: IPlaneConfig, objVisibility: boolean) { const root = new Object3D(); root.name = "root-" + name; this.scene.add(root); const ARVideo: HTMLVideoElement = document.getElementById(id) as HTMLVideoElement; const texture = new VideoTexture(ARVideo as HTMLVideoElement); const mat = new MeshStandardMaterial({ color: 0xbbbbff, map: texture }); const planeGeom = new PlaneGeometry(configs.w, configs.h, configs.ws, configs.hs); const plane = new Mesh(planeGeom, mat); plane.scale.set(scale, scale, scale); this.target.addEventListener("getNFTData-" + this.uuid + "-" + name, (ev: any) => { var msg = ev.detail; plane.position.y = ((msg.height / msg.dpi) * 2.54 * 10) / 2.0; plane.position.x = ((msg.width / msg.dpi) * 2.54 * 10) / 2.0; }); root.add(plane); this.target.addEventListener("getMatrixGL_RH-" + this.uuid + "-" + name, (ev: any) => { setTimeout(() => { ARVideo.play(); root.visible = true; plane.visible = true; root.matrixAutoUpdate = false; }, 100); Utils.setMatrix(root.matrix, ev.detail.matrixGL_RH); }); this.target.addEventListener("nftTrackingLost-" + this.uuid + "-" + name, (ev: any) => { root.visible = objVisibility; plane.visible = objVisibility; ARVideo.pause(); }); this.names.push(name); } /** * You can get the names of the entities used in your project. * @returns the names of the entities */ public getNames() { return this.names; } }