Reputation: 1
I have a basic react homepage with a logo and a rotating 3d globe. I had orbit controls working, but since I added a signup button. I had the orbit controls because my friend wanted to be able to manipulate the globe. I will add more features later, but right now I just want the orbit to work. Also, it seems every other time I load the page, the clouds don't rotate with the globe. They are on separate geometries, and are set to rotate at the same speed.
This is my jsx and css
import React, { useEffect, useRef, useState } from 'react';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import backgroundImage from '../../images/background.png';
import logo from '../../images/logo.png';
import colorMapImage from '../../images/colorMap.png';
import bumpMapImage from '../../images/bumpMap.png';
import cloudMapImage from '../../images/cloudMap.png';
import './HomePage.css';
import SignInSignUpForm from '../components/SignInSignUpForm';
import ChatbotPopup from '../components/ChatbotPopup'; // Import your ChatbotPopup component
function HomePage({ onSignIn, onSignUp }) {
const logoRef = useRef(null);
const modelRef = useRef(null);
const [loading, setLoading] = useState(true);
const globeRef = useRef(null);
const cloudsRef = useRef(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const [isChatbotOpen, setIsChatbotOpen] = useState(false); // State for ChatbotPopup
useEffect(() => {
const logoContainer = logoRef.current;
if (!logoContainer) {
console.error("Logo container not found");
return;
}
console.log("Initializing Three.js scene...");
// Scene setup
const scene = new THREE.Scene();
// Camera setup
const camera = new THREE.PerspectiveCamera(60, logoContainer.clientWidth / logoContainer.clientHeight, 0.1, 1000);
camera.position.set(0, 0, 3);
console.log("Camera created:", camera);
// Renderer setup
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(logoContainer.clientWidth, logoContainer.clientHeight);
renderer.setClearColor(0x000000, 0);
console.log("Renderer created:", renderer);
if (modelRef.current) {
modelRef.current.appendChild(renderer.domElement);
console.log("Renderer appended to model container");
} else {
console.error("Model container not found");
}
// OrbitControls setup
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.enableZoom = true; // Enable zoom
controls.enablePan = false; // Disable panning
controls.target.set(0, 0, 0);
controls.update();
console.log("OrbitControls initialized:", controls);
// Texture loader
const textureLoader = new THREE.TextureLoader();
const colorMap = textureLoader.load(colorMapImage);
const bumpMap = textureLoader.load(bumpMapImage);
const cloudMap = textureLoader.load(cloudMapImage, () => {
// Ensure cloud texture is loaded before adding it to the scene
const cloudGeometry = new THREE.SphereGeometry(0.88, 64, 64); // Updated size
const cloudMaterial = new THREE.MeshStandardMaterial({
map: cloudMap,
transparent: true,
opacity: 0.8, // Updated opacity to 0.8
});
const clouds = new THREE.Mesh(cloudGeometry, cloudMaterial);
cloudsRef.current = clouds;
scene.add(clouds);
console.log("Clouds added to scene:", clouds);
});
// Globe geometry and material with textures
const earthGeometry = new THREE.SphereGeometry(0.86, 64, 64); // Updated size
const earthMaterial = new THREE.MeshStandardMaterial({
map: colorMap,
bumpMap: bumpMap,
bumpScale: 0.1, // Reduced bump scale for realistic effect
metalness: 0.4,
roughness: 0.5,
});
const globe = new THREE.Mesh(earthGeometry, earthMaterial);
globeRef.current = globe;
scene.add(globe);
console.log("Globe added to scene:", globe);
// Light setup
const ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(ambientLight);
console.log("Ambient light added:", ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
directionalLight.position.set(5, 5, 5);
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
directionalLight.shadow.bias = -0.005;
scene.add(directionalLight);
console.log("Directional light added:", directionalLight);
// Shadow settings
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
globe.castShadow = true;
globe.receiveShadow = true;
// Animation loop
const animate = () => {
requestAnimationFrame(animate);
globe.rotation.y += 0.005;
if (cloudsRef.current) {
cloudsRef.current.rotation.y += 0.005; // Rotate clouds at the same speed as the globe
}
controls.update();
renderer.render(scene, camera);
};
animate();
setLoading(false);
// Handle window resize
const handleResize = () => {
camera.aspect = logoContainer.clientWidth / logoContainer.clientHeight;
camera.updateProjectionMatrix();
renderer.setSize(logoContainer.clientWidth, logoContainer.clientHeight);
console.log("Window resized, updated camera and renderer");
};
window.addEventListener('resize', handleResize);
// Open ChatbotPopup after 5 seconds
const chatbotTimeout = setTimeout(() => {
setIsChatbotOpen(true);
}, 5000);
// Cleanup function
return () => {
window.removeEventListener('resize', handleResize);
clearTimeout(chatbotTimeout);
if (modelRef.current) {
modelRef.current.removeChild(renderer.domElement);
console.log("Cleanup: Removed renderer from model container");
}
};
}, []);
const openModal = () => {
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
};
const closeChatbotPopup = () => {
setIsChatbotOpen(false);
};
return (
<div className="homePage">
<div className="mainContent" style={{ backgroundImage: `url(${backgroundImage})` }}>
<div className="logo-container" ref={logoRef}>
<img src={logo} alt="Logo" className="logo-image" />
<div className="model-container" ref={modelRef}></div>
{loading && <div className="loading">Loading...</div>}
</div>
<button className="open-modal-button" onClick={openModal}>Sign In / Sign Up</button>
{isModalOpen && (
<div id="myModal" className="modal">
<SignInSignUpForm closeModal={closeModal} onSignIn={onSignIn} onSignUp={onSignUp} />
</div>
)}
{isChatbotOpen && <ChatbotPopup closePopup={closeChatbotPopup} />} {/* Pass the close function as a prop */}
</div>
</div>
);
}
export default HomePage;
.homePage {
position: relative;
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-size: cover; /* Ensure background covers the entire area */
}
.mainContent {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center; /* Center align the text inside the main content */
}
.logo-container {
position: relative;
width: 80%;
max-width: 800px;
height: 60vh; /* Ensure the height is sufficient to contain the 3D model and logo */
text-align: center;
display: flex;
justify-content: center;
align-items: center; /* Center the content vertically */
cursor: pointer; /* Pointer cursor on hover */
}
.logo-container:hover {
cursor: pointer;
}
.logo-image {
width: 100%;
max-width: 472px; /* Increase the maximum width to approximately 9% larger */
position: relative; /* Ensure relative positioning for absolute child elements */
}
.model-container {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
pointer-events: all; /* Enable pointer events */
z-index: 1; /* Ensure it is above the background but below any foreground elements */
}
.loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 24px;
}
/* Modal styles */
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 2; /* Ensure it is above the model */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
.modal-content {
background-color: #fefefe;
margin: auto; /* Centered */
padding: 20px;
border: 1px solid #888;
width: 80%; /* Could be more or less, depending on screen size */
max-width: 600px;
border-radius: 10px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
.open-modal-button {
padding: 10px 20px;
margin-top: 10px; /* Reduce the margin-top for the sign-up button */
background-color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
Upvotes: 0
Views: 62