Matthew Zuern
Matthew Zuern

Reputation: 1

I'm having three.js rendering and orbit control issues

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

Answers (0)

Related Questions