diff --git a/src/App.jsx b/src/App.jsx index 39f98b4..c94af63 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -2,102 +2,180 @@ import * as THREE from 'three'; import { OrbitControls } from 'three-orbitcontrols-ts'; import { gsap } from "gsap"; import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer'; +import { useEffect } from 'react'; -let camera, scene, renderer, labelRenderer; +let camera, scene, renderer, labelRenderer, currentTexture, currentMaterial; +const ENTITY_NAME = 'sphere' init(); animate(); -function init() { - scene = new THREE.Scene(); +function createSphere(radius, widthS, heightS, texture, material, isVisible = false){ + const sphere = new THREE.SphereGeometry(radius, widthS, heightS) + sphere.scale( - 1, 1, 1 ); + texture.colorSpace = THREE.SRGBColorSpace; + + material.transparent = true + material.opacity = isVisible ? 1 : 0 + + const mesh = new THREE.Mesh(sphere, material) + mesh.position.set(4.5, 2, 4.5) + mesh.name = ENTITY_NAME + + scene.add(mesh) +} + +function removeEntity(entityName) { + var selectedEntity = scene.getObjectByName(entityName); + if(selectedEntity){ + scene.remove( selectedEntity ); + } +} + +function createPoint(title, x, y, z){ + const label = document.createElement('p') + label.textContent = title + label.style.backgroundColor = '#fff' + label.style.borderRadius = '50%' + label.style.height = '60px' + label.style.width = '60px' + label.style.textAlign = 'center' + label.style.pointerEvents = 'auto' + label.style.cursor = 'pointer' + + const cPointLabel = new CSS2DObject(label) + cPointLabel.name = title + scene.add(cPointLabel) + + cPointLabel.position.set(x, y, z) + + return label +} + +function createScene(){ const container = document.getElementById('root'); + scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 2, 1100 ); - camera.position.set(5,2,4.5) - - const geometry = new THREE.SphereGeometry( 5, 60, 40 ); - const largeGeometry = new THREE.SphereGeometry( 10, 60, 40 ); - geometry.scale( - 1, 1, 1 ); - largeGeometry.scale( - 1, 1, 1 ); - - const texture = new THREE.TextureLoader().load( '/src/assets/sea.jpg' ); - texture.colorSpace = THREE.SRGBColorSpace; - const texture1 = new THREE.TextureLoader().load( '/src/assets/podval.jpg' ); - texture1.colorSpace = THREE.SRGBColorSpace; - const material = new THREE.MeshBasicMaterial( { map: texture1 } ); - const material1 = new THREE.MeshBasicMaterial( { map: texture } ); - - const mesh = new THREE.Mesh( geometry, material ); - const meshLarge = new THREE.Mesh( largeGeometry, material ); - const mesh1 = new THREE.Mesh( geometry, material1 ); - const mesh1Large = new THREE.Mesh( largeGeometry, material1 ); - - mesh.position.set(4.5,2,4.5) - meshLarge.position.set(4.5,2,4.5) - mesh1.position.set(23.5,2,4.5) - mesh1Large.position.set(23.5,2,4.5) - - scene.add( meshLarge ); - scene.add( mesh1Large ); + camera.position.set(5, 2, 4.5) renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); container.appendChild( renderer.domElement ); - - const controls = new OrbitControls(camera, renderer.domElement) - controls.update() - controls.target.set(4.5, 2, 4.5) - controls.maxPolarAngle = Math.PI / 2.1 - controls.rotateSpeed = 0.95 labelRenderer = new CSS2DRenderer(); labelRenderer.setSize(window.innerWidth, window.innerHeight); labelRenderer.domElement.style.position = 'absolute' labelRenderer.domElement.style.top = '0px' labelRenderer.domElement.style.pointerEvents = 'none' - document.body.appendChild(labelRenderer.domElement); + container.appendChild(labelRenderer.domElement); - const p = document.createElement('p') - p.textContent = 'Sea' - p.style.backgroundColor = '#fff' - p.style.borderRadius = '50%' - + const controls = new OrbitControls(camera, renderer.domElement) + controls.update() + controls.target.set(4.5, 2, 4.5) + controls.maxPolarAngle = Math.PI / 2.1 + controls.rotateSpeed = 0.95 +} - p.style.height = '50px' - p.style.width = '50px' - p.style.textAlign = 'center' - p.style.verticalAlign = 'middle' - p.style.pointerEvents = 'auto' - p.style.cursor = 'pointer' - const cPointLabel = new CSS2DObject(p) - scene.add(cPointLabel) - cPointLabel.position.set(9, 2.1, 4.5) +function init() { + createScene() - let isMoved = false; - p.addEventListener('click', () => { - if(!isMoved){ - controls.target.set(23.5, 2, 4.5) - p.textContent = 'House' - gsap.to(camera.position, {x: 24, y: 2, z: 4.5, duration: 1.5}) - isMoved = true - } - else if(isMoved){ - gsap.to(camera.position, {x: 5, y: 2, z: 4.5, duration: 1.5}) - p.textContent = 'Sea' - controls.target.set(4.5, 2, 4.5) - isMoved = false - } + const firstTexture = new THREE.TextureLoader().load( '/src/assets/sea.jpg' ); + const firstMaterial = new THREE.MeshBasicMaterial( { map: firstTexture } ); + + const secondTexture = new THREE.TextureLoader().load( '/src/assets/podval.jpg' ); + const secondMaterial = new THREE.MeshBasicMaterial( { map: secondTexture } ); + + const thirdTexture = new THREE.TextureLoader().load( '/src/assets/loc3.jpg' ); + const thirdMaterial = new THREE.MeshBasicMaterial( { map: thirdTexture } ); + + currentTexture = firstTexture + currentMaterial = firstMaterial + + createSphere(5, 60, 40, firstTexture, firstMaterial, true); + + const firstPoint = createPoint('Loc 1', 9, 2.1, 4.5) + const secondPoint = createPoint('Loc 2', -9, 2.1, 4.5) + const thirdPoint = createPoint('Loc 3', -12, 2.1, 11.5) + + secondPoint.style.opacity = 0 + + firstPoint.addEventListener('click', () => { + const timeline = gsap.timeline() + + createSphere(5, 60, 40, secondTexture, secondMaterial) + + timeline + .to(currentTexture, {opacity: 0, + onComplete: () => { + firstPoint.style.opacity = 0 + secondPoint.style.opacity = 1 + thirdPoint.style.opacity = 1 + + currentTexture = secondTexture + currentMaterial = secondMaterial + + removeEntity(ENTITY_NAME) + }}) + .to(secondMaterial, {opacity: 1}) + + + }) + + secondPoint.addEventListener('click', () => { + const timeline = gsap.timeline() + + createSphere(5, 60, 40, firstTexture, firstMaterial) + + + timeline + .to(currentTexture, {opacity: 0, + onComplete: () => { + firstPoint.style.opacity = 1 + secondPoint.style.opacity = 0 + thirdPoint.style.opacity = 1 + + currentTexture = firstTexture + currentMaterial = firstMaterial + + removeEntity(ENTITY_NAME) + }}) + .to(firstMaterial, {opacity: 1}) + + + }) + + thirdPoint.addEventListener('click', () => { + const timeline = gsap.timeline() + + createSphere(5, 60, 40, thirdTexture, thirdMaterial) + + timeline + .to(currentTexture, {opacity: 0, + onComplete: () => { + firstPoint.style.opacity = 1 + secondPoint.style.opacity = 1 + thirdPoint.style.opacity = 0 + + currentTexture = thirdTexture + currentMaterial = thirdMaterial + + removeEntity(ENTITY_NAME) + }}) + .to(thirdMaterial, {opacity: 1}) + + + + }) } function animate() { - requestAnimationFrame( animate ); update(); - } function update() { diff --git a/src/assets/loc3.jpg b/src/assets/loc3.jpg new file mode 100644 index 0000000..db23284 Binary files /dev/null and b/src/assets/loc3.jpg differ diff --git a/src/main.jsx b/src/main.jsx index 2ed3d73..c995655 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -6,7 +6,7 @@ import './index.css' ReactDOM.createRoot(document.getElementById('root')).render( - + {/* */} {/* */} , )