Camera Poses
Visualises the camera poses that were used to reconstruct the capture: it loads the pose list from the capture and renders one tetrahedron marker per camera using a single THREE.js InstancedMesh, colouring each instance along an HSL gradient so you can read the order of the capture path at a glance.
Source Code#
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" />
<title>Teleport.js Camera Poses Sample</title>
<style>
body { margin: 0; overflow: hidden; background: #222; }
canvas { display: block; width: 100vw; height: 100vh; }
</style>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.180.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.180.0/examples/jsm/",
"teleport": "https://d1ziouw89q7sp5.cloudfront.net/teleport-js/0.0.2/teleport.module.js"
}
}
</script>
</head>
<body>
<script type="module">
import * as THREE from "three";
import * as TELEPORT from "teleport";
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 10000);
const renderer = new THREE.WebGLRenderer({ antialias: false, logarithmicDepthBuffer: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
const teleportManager = new TELEPORT.Manager({ renderer: renderer, scene: scene, camera: camera });
let captureLoaded = false;
teleportManager.addEventListener("captureLoaded", () => { captureLoaded = true; });
const capture = await teleportManager.loadCapture("524ee89f293a4a2e907009191ba7b9f4");
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const cameras = await capture.loadCameras();
const totalCameras = cameras.length;
const cameraMarkerGeometry = new THREE.TetrahedronGeometry(5.1);
// 1. Use a single material that supports instance-level coloring
const cameraMarkerMaterial = new THREE.MeshStandardMaterial({ roughness: 0.3, metalness: 0.1, flatShading: true });
// 2. Create the InstancedMesh container
const instancedMarkers = new THREE.InstancedMesh(cameraMarkerGeometry, cameraMarkerMaterial, totalCameras);
// Temporary objects to avoid allocating memory inside the loop
const dummyMatrix = new THREE.Matrix4();
const dummyPosition = new THREE.Vector3();
const dummyRotation = new THREE.Quaternion();
const dummyScale = new THREE.Vector3(1, 1, 1);
const markerColor = new THREE.Color();
cameras.forEach((cam, index) => {
// A. Compute the color gradient along the path
const factor = index / (totalCameras - 1 || 1);
markerColor.setHSL(factor * 0.7, 0.9, 0.5);
// Set the color for this specific instance
instancedMarkers.setColorAt(index, markerColor);
// B. Compute the spatial transformation matrix
dummyPosition.copy(cam.position);
// If cam.rotation is a THREE.Euler, convert it to a Quaternion for matrix composition
if (cam.rotation instanceof THREE.Euler) {
dummyRotation.setFromEuler(cam.rotation);
} else {
dummyRotation.copy(cam.rotation);
}
dummyMatrix.compose(dummyPosition, dummyRotation, dummyScale);
// Set the matrix transformation for this specific instance
instancedMarkers.setMatrixAt(index, dummyMatrix);
});
// 3. Notify Three.js that the instance arrays have changed and need updating on the GPU
instancedMarkers.instanceMatrix.needsUpdate = true;
if (instancedMarkers.instanceColor)
instancedMarkers.instanceColor.needsUpdate = true;
// Optional: Storing data for raycasting/interaction later
instancedMarkers.userData = { isCameraPath: true, cameras: cameras };
scene.add(instancedMarkers);
camera.position.set(0, 600, 800);
camera.updateProjectionMatrix();
camera.lookAt(new THREE.Vector3(0, 0, 250));
window.addEventListener("resize", () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
</script>
</body>
</html>