diff --git a/index.html b/index.html
index 8414e6a..845e948 100644
--- a/index.html
+++ b/index.html
@@ -4,9 +4,18 @@
My first three.js app
diff --git a/interaction.js b/interaction.js
index 92541f4..c199d75 100644
--- a/interaction.js
+++ b/interaction.js
@@ -1,5 +1,5 @@
import * as THREE from "three";
-import { render } from "./main.js";
+import { render, renderer } from "./main.js";
import { getAllImages } from "./single-image-loader.js";
import { createPlane, setScene as setPlaneScene } from "./plane.js";
import { createSphere, setScene as setSphereScene } from "./sphere.js";
@@ -78,12 +78,23 @@ function onClick() {
event.preventDefault();
// Avoid clicking images behind GUI
if (event.target.tagName !== "CANVAS") return;
- mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
+ // get x,y coords into canvas where click occurred
+ var rect = event.target.getBoundingClientRect();
+ var x = event.clientX - rect.left;
+ var y = event.clientY - rect.top;
+ mouse.x = (x / event.target.clientWidth) * 2 - 1;
+ mouse.y = -(y / event.target.clientHeight) * 2 + 1;
+
+ /*mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
+ */
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObject(scene, true);
- if (intersects.length == 0) return;
+ if (intersects.length == 0) {
+ console.log("No intersection detected.");
+ return;
+ }
if (!authoringMode) {
openFigure(intersects);
@@ -153,8 +164,19 @@ function onHover() {
event.preventDefault();
// Avoid clicking images behind GUI
if (event.target.tagName !== "CANVAS") return;
+
+ // get x,y coords into canvas where click occurred
+ var rect = event.target.getBoundingClientRect();
+ var x = event.clientX - rect.left;
+ var y = event.clientY - rect.top;
+ mouse.x = (x / event.target.clientWidth) * 2 - 1;
+ mouse.y = -(y / event.target.clientHeight) * 2 + 1;
+
+ /*
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
- mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
+ mouse.y = -(event.clientY / (window.innerHeight)) * 2 + 1;
+ */
+ //console.log(mouse);
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObject(scene, true);
if (intersects.length > 0) {
@@ -188,7 +210,7 @@ function createJSON(objectArray) {
objectArray.forEach((object) => {
const real_pos = get2DCoords(C, object.position);
- if (object.userData.intersection == null) intersection_pos = real_pos;
+ //if (object.userData.intersection == null) intersection_pos = real_pos;
const intersection_pos = get2DCoords(C, object.userData.intersection);
json.push({
name: object.name,
diff --git a/main.js b/main.js
index e49e335..13a8051 100644
--- a/main.js
+++ b/main.js
@@ -12,6 +12,7 @@ import { setScene } from "./inspect.js";
THREE.Cache.enabled = true;
const scene = new THREE.Scene();
+window.scene = scene; // debug from console
scene.background = new THREE.Color(0xdadada);
const camera = new THREE.PerspectiveCamera(
@@ -25,7 +26,7 @@ camera.position.set(5, 5, 5);
const renderer = new THREE.WebGLRenderer({
antialias: true,
});
-renderer.setSize(window.innerWidth, window.innerHeight - 25);
+renderer.setSize(window.innerWidth, window.innerHeight - 25, false); // -25 to avoid scroll bar
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
@@ -55,6 +56,12 @@ scene.add(axesHelper);
createPanel();
+await loadImages(
+ scene,
+ "out-files/MNAC-AbsidiolaSud/MNAC-AbsSud-CamerasList-converted.lst",
+ "out-files/MNAC-AbsidiolaSud/MNAC-AbsSud-CamerasRegistration.out"
+);
+
//MODEL LOADER
const gltfLoader = new GLTFLoader();
//gltfLoader.load("models/pedret10/MNAC-AbsSud-LowPoly.glb", (object) => {
@@ -77,32 +84,31 @@ gltfLoader.load("models/pedret/pedret_XII_text4K.glb", (object) => {
0.0,
1.0
);
- const pos = new THREE.Vector3().setFromMatrixPosition(matrix);
- const scale = new THREE.Vector3().setFromMatrixScale(matrix);
- const rotation = new THREE.Quaternion().setFromRotationMatrix(matrix);
+ const rotMat = new THREE.Matrix4().copy(matrix);
+ rotMat.premultiply(new THREE.Matrix4().makeRotationX(-Math.PI / 2));
+ const pos = new THREE.Vector3().setFromMatrixPosition(rotMat);
+ const scale = new THREE.Vector3().setFromMatrixScale(rotMat);
+ const rotation = new THREE.Quaternion().setFromRotationMatrix(rotMat);
console.log(object.scene);
object.scene.position.copy(pos);
object.scene.scale.copy(scale);
object.scene.quaternion.copy(rotation);
-
object.scene.name = "model";
-
+ //console.log("Before:", object.scene.matrixWorld);
+ /*
const wrapper = new THREE.Object3D();
- wrapper.name = "model";
+ wrapper.name = "wrapper";
wrapper.add(object.scene);
- wrapper.rotateX(-Math.PI / 2);
-
- scene.add(wrapper);
+ //wrapper.rotateX(-Math.PI / 2);
+ scene.add(wrapper);*/
+ scene.add(object.scene);
+ //setIntersectionPosition(object.scene);
setIntersectionPosition(scene);
});
-await loadImages(
- scene,
- "out-files/MNAC-AbsidiolaSud/MNAC-AbsSud-CamerasList-converted.lst",
- "out-files/MNAC-AbsidiolaSud/MNAC-AbsSud-CamerasRegistration.out"
-);
+
addInteraction(camera, scene, controls);
@@ -131,4 +137,4 @@ function render() {
animate();
-export { render };
+export { render, renderer };
diff --git a/multiple-image-loader.js b/multiple-image-loader.js
index cb227b7..a9fbec8 100644
--- a/multiple-image-loader.js
+++ b/multiple-image-loader.js
@@ -24,7 +24,7 @@ async function loadImages(scene, images_file, cameras_file) {
const out_file_loader = new THREE.FileLoader();
out_file_loader.load(cameras_file, function (data) {
const lines = data.split("\n");
- const num_cameras = lines[1].split(" ")[0];
+ const num_cameras = lines[1].split(" ")[0]; // TODO
for (let i = 0; i < num_cameras; i++) {
const line_number = 2 + 5 * i;
@@ -34,6 +34,7 @@ async function loadImages(scene, images_file, cameras_file) {
const focalLength = lines[line_number].split(" ").map(parseFloat)[0];
const zoom = math.sqrt(focalLength / min_focal);
+ //zoom *= 2; // TODO testing
const R = math.matrix([
lines[line_number + 1].split(" ").map(parseFloat),
@@ -41,6 +42,9 @@ async function loadImages(scene, images_file, cameras_file) {
lines[line_number + 3].split(" ").map(parseFloat),
]);
const t = math.matrix(lines[line_number + 4].split(" ").map(parseFloat));
+
+ //if (!image_list[i].includes("0098")) continue; // TODO
+
loadImage(scene, R, t, zoom, image_list[i], image_loader);
}
});
diff --git a/openseadragon.html b/openseadragon.html
index 8779264..be69895 100644
--- a/openseadragon.html
+++ b/openseadragon.html
@@ -8,12 +8,10 @@
diff --git a/openseadragon.js b/openseadragon.js
index 0cae8ae..db9fe6a 100644
--- a/openseadragon.js
+++ b/openseadragon.js
@@ -8,6 +8,7 @@ const parsedImages = JSON.parse(retrievedObject);
var overlapping;
var regularZoom = true;
var realPosition = true;
+var overlappingSet = false;
console.log(mode);
console.log(image);
@@ -37,8 +38,6 @@ if (mode === "single") {
}
var viewer = OpenSeadragon({
- zoomInButton: "zoom-in",
- zoomOutButton: "zoom-out",
homeButton: "home",
fullPageButton: "full-page",
@@ -48,13 +47,14 @@ var viewer = OpenSeadragon({
showNavigator: true,
preserveViewport: true,
+ maxZoomPixelRatio: 3, // for videos
});
viewer.zoomPerClick = 1;
viewer.addHandler("open", function () {
if (mode === "single" || parsedImages.size == 1) return;
- distribute(parsedImages);
+ //distribute(parsedImages); // testing
});
viewer.addHandler("canvas-click", function (event) {
@@ -84,7 +84,25 @@ viewer.addHandler("canvas-click", function (event) {
}
});
+function distrib() {
+ if (mode === "single" || parsedImages.size == 1) return;
+ overlappingSet = !overlappingSet;
+
+ if (overlappingSet) {
+ document.getElementById("overlap").style.display = "inline";
+ document.getElementById("distribute").style.display = "none";
+ } else {
+ document.getElementById("overlap").style.display = "none";
+ document.getElementById("distribute").style.display = "inline";
+ }
+
+ recalculate();
+ distribute(parsedImages);
+}
+
function distribute(images) {
+ if (!overlappingSet) return;
+ //return; // TODO
overlapping = true;
for (let i = 0; overlapping; i++) {
console.log("i: " + i);
@@ -128,6 +146,12 @@ function getIntersection(a, b) {
var right = min(getRight(a), getRight(b));
var bottom = max(getBottom(a), getBottom(b));
+ const margin = 0.01;
+ left -= margin;
+ right += margin;
+ top += margin;
+ bottom -= margin;
+
if (bottom < top && right > left) {
return {
top: top,
@@ -143,8 +167,9 @@ function getIntersection(a, b) {
}
function moveImage(a, output, i) {
- a.x += output.x;
- a.y += output.y;
+ const speed = 1.0; // testing
+ a.x += output.x * speed;
+ a.y += output.y * speed;
var item = viewer.world.getItemAt(i);
item.setPosition(new OpenSeadragon.Point(a.x - getWidth(a) / 2, a.y - getHeight(a) / 2));
}
@@ -178,6 +203,9 @@ function togglePosition() {
}
function recalculate() {
+ console.log(
+ "Recalculating. Real position: " + realPosition + ". Regular zoom: " + regularZoom + "."
+ );
for (let i = 0; i < parsedImages.length; i++) {
const a = parsedImages[i];
var item = viewer.world.getItemAt(i);
diff --git a/package-lock.json b/package-lock.json
index dd4c73c..e0a6f41 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,7 +6,8 @@
"": {
"dependencies": {
"mathjs": "^12.3.1",
- "three": "^0.161.0"
+ "three": "^0.165.0",
+ "three-mesh-bvh": "^0.7.5"
},
"devDependencies": {
"vite": "^5.0.12"
@@ -783,9 +784,17 @@
}
},
"node_modules/three": {
- "version": "0.161.0",
- "resolved": "https://registry.npmjs.org/three/-/three-0.161.0.tgz",
- "integrity": "sha512-LC28VFtjbOyEu5b93K0bNRLw1rQlMJ85lilKsYj6dgTu+7i17W+JCCEbvrpmNHF1F3NAUqDSWq50UD7w9H2xQw=="
+ "version": "0.165.0",
+ "resolved": "https://registry.npmjs.org/three/-/three-0.165.0.tgz",
+ "integrity": "sha512-cc96IlVYGydeceu0e5xq70H8/yoVT/tXBxV/W8A/U6uOq7DXc4/s1Mkmnu6SqoYGhSRWWYFOhVwvq6V0VtbplA=="
+ },
+ "node_modules/three-mesh-bvh": {
+ "version": "0.7.5",
+ "resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.7.5.tgz",
+ "integrity": "sha512-WDd77RklE52pZSKZx8sDXzrd2JCF/gL/hugFvsIBylpMRlJxxwesKn2rW7TcQZ809NocDVkQx1UJo9pJtVAPYg==",
+ "peerDependencies": {
+ "three": ">= 0.151.0"
+ }
},
"node_modules/tiny-emitter": {
"version": "2.1.0",
diff --git a/package.json b/package.json
index 7114204..3283552 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,8 @@
{
"dependencies": {
"mathjs": "^12.3.1",
- "three": "^0.161.0"
+ "three": "^0.165.0",
+ "three-mesh-bvh": "^0.7.5"
},
"devDependencies": {
"vite": "^5.0.12"
diff --git a/single-image-loader.js b/single-image-loader.js
index 7b64db7..c0d23d4 100644
--- a/single-image-loader.js
+++ b/single-image-loader.js
@@ -1,14 +1,23 @@
import * as THREE from "three";
import { create, all } from "mathjs";
+import { MeshBVH, acceleratedRaycast, computeBoundsTree, disposeBoundsTree } from "three-mesh-bvh"; // BVH
+THREE.Mesh.prototype.raycast = acceleratedRaycast;
+THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
+THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;
+
const math = create(all, {});
var raycaster = new THREE.Raycaster();
+raycaster.params.Line.threshold = 0.001;
+
var imageOffset = 0.2;
var imageSize = 1;
var images = [];
+const pickableObjects = [];
+
function loadImage(scene, R, t, zoom, image_name, image_loader) {
const pos = math.multiply(math.unaryMinus(math.transpose(R)), t);
//View direction
@@ -60,7 +69,7 @@ function loadImage(scene, R, t, zoom, image_name, image_loader) {
color: 0x0000ff,
transparent: true,
opacity: 0.5,
- linewidth: 0.1,
+ linewidth: 0.2,
});
const line = new THREE.Line(geometry, material);
line.name = "wireframe-line";
@@ -95,6 +104,15 @@ function loadImage(scene, R, t, zoom, image_name, image_loader) {
isLandscape: isLandscape,
heightToWidthRatio: heightToWidthRelation,
};
+ console.log(
+ "Image: ",
+ image_name,
+ " Position: ",
+ image_plane.position,
+ " Direction: ",
+ image_plane.userData.direction
+ );
+
images.push(image_plane);
});
}
@@ -132,24 +150,74 @@ function setWireframe(enable) {
}
function setIntersectionPosition(scene) {
+ console.log(scene);
+
+ var gltf = scene.getObjectByName("model");
+ gltf.updateMatrixWorld(true);
+ gltf.traverse(function (child) {
+ if (child.isMesh) {
+ const m = child; // as THREE.Mesh
+ m.geometry.computeBoundsTree(); // BVH
+ pickableObjects.push(m);
+ }
+ });
+ console.log("Pick:", pickableObjects);
+
+ var model = scene.getObjectByName("model");
+ //var model = scene;
+ console.log(model);
+ console.log("Setting intersection positions for ", images.length, " images...");
+
images.forEach((i) => {
const intersectionPosition = getIntersectionPosition(
scene,
+ model,
+ pickableObjects,
i.position,
i.userData.direction
);
i.userData.intersection = new THREE.Vector3().copy(intersectionPosition);
});
+ console.log("Setting intersection positions: done!");
}
-function getIntersectionPosition(scene, position, direction) {
+function getIntersectionPosition(scene, model, objs, position, direction) {
raycaster.set(position, direction);
- var intersections = raycaster.intersectObject(scene, true);
- if (intersections.length == 0) return position;
- for (let i = 0; i < intersections.length; i++) {
- if (intersections[i].object.name != "wireframe") return intersections[i].point;
+ console.log("Position: ", position, " Direction: ", direction);
+ raycaster.firstHitOnly = true; // BVH
+ //var intersections = raycaster.intersectObjects(model, true); // BVH
+ /*
+ const invMat = new THREE.Matrix4();
+ invMat.copy(model.matrixWorld).invert();
+ raycaster.ray.applyMatrix4(invMat);
+ */
+
+ var intersections = raycaster.intersectObjects(objs, true); // BVH
+
+ if (intersections.length == 0) {
+ console.log("No intersection found");
+ return position;
}
- return position;
+ var i = 0;
+ var j = -1;
+ for (; i < intersections.length; i++) {
+ //if (intersections[i].object.name != "wireframe" && intersections[i].object.name != "wireframe-line" && intersections[i].object.name != "" && intersections[i].object.name[0] != "S") break; // return intersections[i].point;
+ console.log("Intersected:", intersections[i].object);
+ //if (intersections[i].object.name != "wireframe") j = i;
+ if (intersections[i].object.name[0] == "P") {
+ j = i;
+ break; // return intersections[i].point;
+ }
+ }
+ if (j != -1)
+ console.log(
+ "Position: ",
+ position,
+ " Intersection",
+ intersections[j].point,
+ intersections[j].object.name
+ );
+ return intersections[j].point;
}
function setImageVisibility(show) {
diff --git a/sphere.js b/sphere.js
index 64aa7f2..b2d71b0 100644
--- a/sphere.js
+++ b/sphere.js
@@ -56,7 +56,7 @@ function get2DCoords(P) {
const V = new THREE.Vector3().subVectors(P, C).normalize();
const phi = math.acos(V.y);
const theta = math.atan2(V.x, V.z);
- return { x: theta, y: phi };
+ return { x: -theta, y: phi }; // TODO: Check if it is correct
}
function applySphericalRadius(r) {