here is my code :
import React, { useEffect, useState } from ‘react’;
import { useThree } from ‘@react-three/fiber’;
import * as THREE from ‘three’;
interface PanoramaViewerProps {
cubeImages: string;
tileTexture: string; // Add a prop for the texture tile image
}
const PanoramaViewer: React.FC = ({ cubeImages, tileTexture }) => {
const { scene, camera } = useThree();
const [hoveredUV, setHoveredUV] = useState<THREE.Vector2 | null>(null);
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const canvas = document.createElement(‘canvas’);
let texture: THREE.CubeTexture;
useEffect(() => {
// Load the cube texture for the 360 view
const loader = new THREE.CubeTextureLoader();
texture = loader.load(cubeImages, () => {
const img = texture.image[0]; // Assuming the texture images are consistent
canvas.width = img.width;
canvas.height = img.height;
const context = canvas.getContext('2d');
if (context) {
context.drawImage(img, 0, 0, canvas.width, canvas.height);
}
});
// Apply the texture to the background
scene.background = texture;
return () => {
// Cleanup
if (scene.background === texture) {
scene.background = null;
}
};
}, [cubeImages, scene]);
const onMouseMove = (event: MouseEvent) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObject(camera as THREE.Object3D);
if (intersects.length > 0) {
const uv = intersects[0].uv;
if (uv) {
checkTransparencyAtUV(uv);
} else {
setHoveredUV(null);
}
} else {
setHoveredUV(null);
}
};
const checkTransparencyAtUV = (uv: THREE.Vector2) => {
const context = canvas.getContext(‘2d’);
if (!context) return;
const x = Math.floor(uv.x * canvas.width);
const y = Math.floor(uv.y * canvas.height);
if (x < 0 || x >= canvas.width || y < 0 || y >= canvas.height) return;
const pixel = context.getImageData(x, y, 1, 1).data;
if (pixel[3] === 0) {
setHoveredUV(uv);
// Replace transparent area with tile texture
const tileLoader = new THREE.TextureLoader();
tileLoader.load(tileTexture, (tile) => {
const material = new THREE.MeshBasicMaterial({
map: tile,
side: THREE.DoubleSide,
transparent: true,
blending: THREE.MultiplyBlending,
});
// Apply the material to the scene where transparency is detected (optional: modify geometry or mesh here)
// Example: You can apply this to a cube geometry or any object you wish.
});
} else {
setHoveredUV(null);
}
};
useEffect(() => {
window.addEventListener(‘mousemove’, onMouseMove);
return () => {
window.removeEventListener(‘mousemove’, onMouseMove);
};
}, );
return (
<>
{hoveredUV && (
<div style={{ position: ‘absolute’, left: 10, top: 10 }}>
Hovering over transparent area at UV: {hoveredUV.x.toFixed(2)}, {hoveredUV.y.toFixed(2)}
)}
</>
);
};
export default PanoramaViewer;
import React from ‘react’;
import { Canvas } from ‘@react-three/fiber’;
import { OrbitControls } from ‘@react-three/drei’;
import PanoramaViewer from ‘./components/PanoramaViewer’;
// Import the images for the skybox and texture tile
import py from ‘./assets/py.png’;
import px from ‘./assets/px.png’;
import pz from ‘./assets/pz.png’;
import ny from ‘./assets/ny.png’;
import nx from ‘./assets/nx.png’;
import nz from ‘./assets/nz.png’;
import tile from ‘./assets/tile.jpg’; // Tile texture for transparent areas
const App: React.FC = () => {
const cubeImages = [px, nx, py, ny, pz, nz]; // 360° cube images
return (
<div style={{ width: ‘100vw’, height: ‘100vh’ }}>
<pointLight position={[10, 10, 10]} />
{/* 360 Panorama Viewer with tile texture */}
<PanoramaViewer cubeImages={cubeImages} tileTexture={tile} />
{/* Controls to look around */}
<OrbitControls enableZoom={true} />
</Canvas>
</div>
);
};
export default App;