I have a 360 degree panoramic image and i am displaying this image using three js. Now i wanted to display a marker on that 360 degree panoramic image (marker: just like the location marker on map). On zoom in or zoom out the 360 degree image should zomm in or zoom out but the marker mainatain its ideal constant location. The marker should not be zoom in or zoom out. For better understanding the what the actual beheviour i want you can look at the location marker on the google map. Here is the code of How i am displaying the 360 degree image using three js.
import React, { useRef, useEffect, useState } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
import { EVENTS, TYPES, ThreeJsDrawing } from './threeJsDrawing';
import { setThreeJsData } from './mouseEvents';
import panImg from "../assets/shot.jpg";
import panImg2 from "../assets/shot2.jpg";
import panImg3 from "../assets/shot3.png";
import panImg4 from "../assets/shot4.png";
let scene, camera, controls, sphere, polygons = [], drawingTool,
images = [
{
url: panImg,
location: {
x: 369794,
y: 2212918,
lat: 20.008508,
lng: 73.755165
}
},
{
url: panImg2,
location: {
x: 369779,
y: 2212922,
lat: 20.008382,
lng: 73.755117
}
},
{
url: panImg3,
location: {
x: 369769,
y: 2212912,
lat: 20.008251,
lng: 73.755074
}
},
{
url: panImg4,
location: {
x: 369762,
y: 2212895,
lat: 20.008226,
lng: 73.755165
}
}
]
const PanoramaViewer = () => {
const [activeImage, setActiveImage] = useState(null)
const [renderer, setRenderer] = useState(null)
useEffect(() => {
if (activeImage || activeImage === 0) loadImage(activeImage)
}, [activeImage])
const [loading, setLoading] = useState(true)
const containerRef = useRef(null);
const loadImage = (index, initCall) => {
const img = images[index]
const [x, y] = [0, 0]
// Load the panorama texture
const loader = new THREE.TextureLoader();
const texture = loader.load(img.url, (texture) => {
// Texture loaded successfully
// Set the texture wrapping and flipping options
texture.wrapS = THREE.RepeatWrapping;
// texture.repeat.x = -1;
sphere.material.map = texture;
sphere.material.needsUpdate = true; // Ensure material updates
// controls.object.rotation.set(-2.3553, 1.57, 2.3553)
// Optional: Clean up the previous texture resources
sphere.material.map.dispose();
setLoading(false)
});
if (initCall) {
// Create a sphere geometry
const geometry = new THREE.SphereGeometry(5, 32, 32);
geometry.scale(-1, 1, 1);
// Create a material with the panorama texture
const material = new THREE.MeshBasicMaterial({ map: texture });
// Create a mesh with the geometry and material
sphere = new THREE.Mesh(geometry, material);
sphere.position.set(x, y, 0);
// Add the mesh to the scene
scene.add(sphere);
camera.position.set(x, y, 0.1);
controls.target.set(x, y, 0)
controls.update();
}
}
const nextImage = () => {
if (activeImage + 1 < images.length) {
setLoading(true)
setActiveImage(activeImage + 1)
}
}
const prevImage = () => {
if (activeImage - 1 >= 0) {
setLoading(true)
setActiveImage(activeImage - 1)
}
}
const initThreeJs = () => {
// Create a scene
scene = new THREE.Scene();
// Create a camera
camera = new THREE.PerspectiveCamera(
75,
containerRef.current.clientWidth / containerRef.current.clientHeight,
1,
1000
);
// Create a renderer
const renderer = new THREE.WebGLRenderer();
setRenderer(renderer)
renderer.setSize(containerRef.current.clientWidth, containerRef.current.clientHeight);
containerRef.current.appendChild(renderer.domElement);
// Add orbit controls for rotation
controls = new OrbitControls(camera, renderer.domElement);
controls.enableZoom = true;
controls.rotateSpeed = -0.25; // Adjust the value as needed
loadImage(0, true)
setThreeJsData(renderer, scene, camera, controls)
// Render the scene
const animate = () => {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
// Clean up
return () => {
// containerRef.current.removeEventListener('click', handleClick);
containerRef.current.removeChild(renderer.domElement);
controls.dispose();
};
}
useEffect(initThreeJs, []);
const Loader = () => {
return loading ? <div style={{ position: 'absolute', width: "100%", height: "100%", display: "flex", justifyContent: "center", alignItems: "center", color: 'white' }}>Loading...</div> : <></>
}
const markIssue = (type) => {
if (drawingTool) {
console.log("if called", drawingTool)
drawingTool.enableDrawing(type)
drawingTool.on(EVENTS.GEOMETRY_ADDED, (geometry => {
polygons.push(geometry)
}))
}
else {
//activate drawing tool
console.log("else called")
console.log("scene:", scene, "camera:", camera, "sphere:", [sphere])
drawingTool = new ThreeJsDrawing(scene, camera, [sphere], false)
drawingTool.enableDrawing(type)
drawingTool.on(EVENTS.GEOMETRY_ADDED, (geometry => {
console.log("geometry", geometry)
polygons.push(geometry)
}))
console.log("polygon arrayyy:", polygons)
}
}
return <>
<Loader />
<div style={{ position: "absolute", display: "flex", width: "100%", height: "40px", alignItems: 'center', justifyContent: 'space-around', background: "#00000082", color: 'white' }}>
<div onClick={prevImage} style={{ cursor: "pointer" }}>prevImage</div>
<div onClick={nextImage} style={{ cursor: "pointer" }}>nextImage</div>
</div>
<div style={{ position: "absolute", display: "flex", width: "100%", height: "40px", bottom: 0, alignItems: 'center', justifyContent: 'space-around', background: "#00000082", color: 'white', cursor: "pointer" }}>
<div onClick={() => {
markIssue("Polygon");
console.log("polygon click")
}}>
polygon
</div>
<div onClick={() => {
markIssue("Rectangle");
console.log("Rectangle click")
}}>
Rectangle
</div>
<div onClick={() => {
markIssue("Hotspot");
console.log("Hotspot clcik")
}}>
Hotspot
</div>
</div>
<div ref={containerRef} style={{ width: '100%', height: '100vh' }} />
</>;
};
export default PanoramaViewer;
I tried using sphere, css2Dobject, texture as a marker but it wont work.
To display a marker on a 360-degree panoramic image using Three.js and ensure that the marker maintains a constant position when you zoom in or out, you can follow these steps:
Here's an updated version of your code with the necessary modifications:
In this code, we create a simple cube marker and add it to the scene. We update the marker's position relative to the camera's position in the animation loop. This ensures that the marker maintains a constant position regardless of zooming in or out.
You can customize the marker's geometry and material to suit your needs. Make sure to adjust the marker's position and size as necessary.