diff --git a/environments.html b/environments.html index 22aa483..fba72bd 100644 --- a/environments.html +++ b/environments.html @@ -46,9 +46,11 @@ let depthRange = 3.0; let resolution = 2; let meshDirty = false; - let environmentMesh; - const resolutions = [512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192] + let rotationGroup; + + const rotation_angle = 30; + const resolutions = [512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192]; init(); animate(); @@ -65,6 +67,9 @@ document.body.appendChild(renderer.domElement); document.body.appendChild(VRButton.createButton(renderer)); + rotationGroup = new THREE.Group(); // Initialize rotation group + scene.add(rotationGroup); + const minDistanceSlider = document.getElementById('minDistance'); const depthRangeSlider = document.getElementById('depthRange'); const resolutionSlider = document.getElementById('meshResolution'); @@ -114,6 +119,9 @@ createEnvironmentMesh(); // Generate new mesh with updated settings } }); + + // Event listener for keyboard input + window.addEventListener('keydown', onKeyDown, false); } async function fetchEnvironments() { @@ -129,14 +137,27 @@ } function loadEnvironmentTextures(environment) { - const textureLoader = new THREE.TextureLoader(); - textureLoader.load(`environments/${environment}/skybox.png`, (texture) => { - environmentTexture = texture; + const imageLoader = new THREE.ImageLoader(); + imageLoader.setCrossOrigin('anonymous'); - textureLoader.load(`environments/${environment}/depth.png`, (texture) => { - depthTexture = texture; - createEnvironmentMesh(); - }); + const skyboxPromise = new Promise((resolve, reject) => { + imageLoader.load(`environments/${environment}/skybox.png`, resolve, undefined, reject); + }); + + const depthPromise = new Promise((resolve, reject) => { + imageLoader.load(`environments/${environment}/depth.png`, resolve, undefined, reject); + }); + + Promise.all([skyboxPromise, depthPromise]).then(([skyboxImage, depthImage]) => { + environmentTexture = new THREE.Texture(skyboxImage); + environmentTexture.needsUpdate = true; + + depthTexture = new THREE.Texture(depthImage); + depthTexture.needsUpdate = true; + + createEnvironmentMesh(); + }).catch((error) => { + console.error('Error loading images:', error); }); } @@ -144,21 +165,21 @@ function createEnvironmentMesh() { // Remove the previous environment mesh if it exists if (environmentMesh) { - scene.remove(environmentMesh); + rotationGroup.remove(environmentMesh); environmentMesh.geometry.dispose(); environmentMesh.material.dispose(); } // Create new sphere geometry with the selected resolution - const verticesTheta = Math.min(resolutions[resolution], depthTexture.image.width) - const verticesPhi = Math.min(resolutions[resolution] / 2, depthTexture.image.height) + const verticesTheta = Math.min(resolutions[resolution], depthTexture.image.width); + const verticesPhi = Math.min(resolutions[resolution] / 2, depthTexture.image.height); const sphereGeometry = new THREE.SphereGeometry(1, verticesTheta, verticesPhi); sphereGeometry.scale(-1, 1, 1); // Invert the sphere const material = new THREE.MeshBasicMaterial({ map: environmentTexture }); environmentMesh = new THREE.Mesh(sphereGeometry, material); - scene.add(environmentMesh); + rotationGroup.add(environmentMesh); // Apply depth distortion to the new geometry applyDepthDistortion(sphereGeometry, depthTexture); @@ -167,9 +188,14 @@ } function applyDepthDistortion(geometry, depthMap) { + const depthData = getDepthData(depthMap); + if (!depthData) { + console.error('Depth data is invalid. Skipping depth distortion.'); + return; + } + const positionAttribute = geometry.attributes.position; const uv = geometry.attributes.uv; - const depthData = getDepthData(depthMap); for (let i = 0; i < positionAttribute.count; i++) { const x = positionAttribute.getX(i); @@ -179,10 +205,11 @@ const u = uv.getX(i); const v = 1 - uv.getY(i); // Flip v coordinate - const depthValue = 1 - sampleDepth(depthData, u, v); // Invert depth value + let depthValue = 1 - sampleDepth(depthData, u, v); // Invert depth value + if (isNaN(depthValue)) depthValue = 0; - // Adjust based on the slider-controlled minDistance and depthRange const distortionFactor = minDistance + depthValue * depthRange; + if (isNaN(distortionFactor)) continue; positionAttribute.setXYZ(i, x * distortionFactor, y * distortionFactor, z * distortionFactor); } @@ -191,12 +218,25 @@ } function getDepthData(depthTexture) { + const image = depthTexture.image; + if (!image || !image.width || !image.height) { + console.error('Depth texture image is not properly loaded.'); + return null; + } + const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); - canvas.width = depthTexture.image.width; - canvas.height = depthTexture.image.height; - ctx.drawImage(depthTexture.image, 0, 0); - return ctx.getImageData(0, 0, canvas.width, canvas.height).data; + canvas.width = image.width; + canvas.height = image.height; + ctx.drawImage(image, 0, 0); + + try { + const data = ctx.getImageData(0, 0, canvas.width, canvas.height).data; + return data; + } catch (e) { + console.error('Failed to get depth data:', e); + return null; + } } function sampleDepth(depthData, u, v) { @@ -204,7 +244,16 @@ const height = depthTexture.image.height; const x = Math.floor(u * width); const y = Math.floor(v * height); + + if (x < 0 || x >= width || y < 0 || y >= height) { + return 0; + } + const index = (y * width + x) * 4; + if (index < 0 || index >= depthData.length) { + return 0; + } + return depthData[index] / 255; // Normalize to 0-1 range } @@ -221,6 +270,36 @@ function render() { renderer.render(scene, camera); } + + // Handle keyboard input + function onKeyDown(event) { + switch (event.code) { + case 'ArrowLeft': + case 'KeyA': + rotateSceneLeft(); + event.preventDefault(); + break; + case 'ArrowRight': + case 'KeyD': + rotateSceneRight(); + event.preventDefault(); + break; + case 'ArrowDown': + case 'ArrowUp': + event.preventDefault(); + break; + } + } + + // Rotate the scene left + function rotateSceneLeft() { + rotationGroup.rotation.y -= THREE.MathUtils.degToRad(rotation_angle); + } + + // Rotate the scene right + function rotateSceneRight() { + rotationGroup.rotation.y += THREE.MathUtils.degToRad(rotation_angle); + } - \ No newline at end of file +