import { ARButton } from "https://threejs.org/examples/jsm/webxr/ARButton.js";
let glb_model;
let camera, scene, renderer, container;
let controller, controls, camera_pos, object_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
);
glb_model = document.querySelector("#glb_model").object3D;
glb_model.visible = false;
object_type = "glb_model";
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"] })
);
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");
if (Math.abs(radians_to_degrees(euler_angle.x)) > 80) {
//placed on the wall
glb_model.visible = true;
glb_model.rotation.x = euler_angle.x;
glb_model.rotation.y = euler_angle.y;
glb_model.rotation.z = euler_angle.z;
glb_model.position.setFromMatrixPosition(reticle.matrix);
}
else {
//placed on the floor
var model_pos = new THREE.Vector3();
glb_model.position.setFromMatrixPosition(reticle.matrix);
glb_model.position.y -= 0.2;
glb_model.visible = true;
glb_model.updateMatrixWorld();
model_pos.setFromMatrixPosition(glb_model.matrixWorld);
glb_model.lookAt(camera_pos.x, model_pos.y, camera_pos.z);
}
}
}
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);
}