import { ARButton } from "https://threejs.org/examples/jsm/webxr/ARButton.js";
let television_floor, television_wall, television_screen;
let projector_plane;
let camera, scene, renderer, container;
let controller, controls, camera_pos, screen_type;
let reticle;
let hitTestSource = null;
let hitTestSourceRequested = false;
init();
animate();
function init() {
camera_pos = new THREE.Vector3();
container = document.createElement("div");
document.body.appendChild(container);
scene = document.querySelector("a-scene").object3D;
camera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
0.01,
20
);
//if it's television
if(document.querySelector("#television_screen") != null){
television_screen = document.querySelector("#television_screen").object3D;
television_screen.visible = false;
screen_type = "television";
}
else{
projector_plane = document.querySelector("#projector_plane").object3D;
projector_plane.visible = false;
screen_type = "projector";
}
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.xr.enabled = true;
container.appendChild(renderer.domElement);
document.body.appendChild(
ARButton.createButton(renderer, { requiredFeatures: ["hit-test"] })
);
if(screen_type == "television"){
television_floor = document.querySelector("#television_floor").object3D;
television_floor.visible = false;
television_wall = document.querySelector("#television_wall").object3D;
television_wall.visible = false;
}
function onSelect() {
if (reticle.visible) {
const material = new THREE.MeshPhongMaterial({
color: 0xffffff * Math.random(),
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.setFromMatrixPosition(reticle.matrix);
mesh.scale.y = Math.random() * 2 + 1;
var quat_angle = new THREE.Quaternion();
reticle.getWorldQuaternion(quat_angle);
var euler_angle = new THREE.Euler().setFromQuaternion(quat_angle, "XYZ");
var video = document.querySelector("#video");
if (video != null) {
video.load();
video.play();
}
if (Math.abs(radians_to_degrees(euler_angle.x)) > 80) {
//placed on the wall
if(screen_type == "television"){
television_wall.visible = true;
television_floor.visible = false;
television_wall.rotation.x = euler_angle.x;
television_wall.rotation.y = euler_angle.y;
television_wall.rotation.z = euler_angle.z;
television_wall.position.setFromMatrixPosition(reticle.matrix);
television_wall.add(television_screen);
television_screen.rotation.x = -1.5708;
television_screen.position.x = 0;
television_screen.position.y = 0.002;
television_screen.position.z = 0;
television_screen.visible = true;
}
else{
projector_plane.visible = true;
projector_plane.rotation.x = euler_angle.x;
projector_plane.rotation.y = euler_angle.y;
projector_plane.rotation.z = euler_angle.z;
projector_plane.rotateX(-1.5708);
projector_plane.position.setFromMatrixPosition(reticle.matrix);
}
} else {
//placed on the floor
if(screen_type == "television"){
var television_pos = new THREE.Vector3();
television_floor.position.setFromMatrixPosition(reticle.matrix);
television_floor.position.y -= 0.1;
television_floor.visible = true;
television_wall.visible = false;
television_floor.updateMatrixWorld();
television_pos.setFromMatrixPosition(television_floor.matrixWorld);
television_floor.lookAt(camera_pos.x, television_pos.y, camera_pos.z);
television_floor.add(television_screen);
television_screen.rotation.x = 0;
television_screen.position.x = 0;
television_screen.position.y = 0.048;
television_screen.position.z = 0.002;
television_screen.visible = true;
}
else{
var plane_pos = new THREE.Vector3();
projector_plane.position.setFromMatrixPosition(reticle.matrix);
projector_plane.position.y -= 0.2;
projector_plane.visible = true;
projector_plane.updateMatrixWorld();
plane_pos.setFromMatrixPosition(projector_plane.matrixWorld);
projector_plane.lookAt(camera_pos.x, plane_pos.y, camera_pos.z);
projector_plane.rotateX(-1.5708);
}
}
}
}
controller = renderer.xr.getController(0);
controller.addEventListener("select", onSelect);
scene.add(controller);
reticle = new THREE.Mesh(
new THREE.RingGeometry(0.15, 0.2, 32).rotateX(-Math.PI / 2),
new THREE.MeshBasicMaterial()
);
reticle.matrixAutoUpdate = false;
reticle.visible = false;
scene.add(reticle);
const geometry = new THREE.CylinderGeometry(0.1, 0.1, 0.2, 32).translate(
0,
0,
0
);
window.addEventListener("resize", onWindowResize);
}
function move_toward_target() {}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function radians_to_degrees(radians) {
var pi = Math.PI;
return radians * (180 / pi);
}
function animate() {
renderer.setAnimationLoop(render);
}
function render(timestamp, frame) {
camera_pos.setFromMatrixPosition(camera.matrixWorld);
if (frame) {
const referenceSpace = renderer.xr.getReferenceSpace();
const session = renderer.xr.getSession();
if (hitTestSourceRequested === false) {
session.requestReferenceSpace("viewer").then(function (referenceSpace) {
session
.requestHitTestSource({ space: referenceSpace })
.then(function (source) {
hitTestSource = source;
});
});
session.addEventListener("end", function () {
hitTestSourceRequested = false;
hitTestSource = null;
});
hitTestSourceRequested = true;
}
if (hitTestSource) {
const hitTestResults = frame.getHitTestResults(hitTestSource);
if (hitTestResults.length) {
const hit = hitTestResults[0];
reticle.visible = true;
reticle.matrix.fromArray(hit.getPose(referenceSpace).transform.matrix);
} else {
reticle.visible = false;
}
}
}
renderer.render(scene, camera);
}