import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js'; import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js'; export function createScene() { // Scene setup const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.setFocalLength(50); const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); // Renderer setup const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(0x000000); renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 1.2; renderer.outputColorSpace = THREE.SRGBColorSpace; renderer.physicallyCorrectLights = true; document.body.appendChild(renderer.domElement); // Post-processing: Bloom const composer = new EffectComposer(renderer); const renderPass = new RenderPass(scene, camera); composer.addPass(renderPass); const bloomPass = new UnrealBloomPass( new THREE.Vector2(window.innerWidth, window.innerHeight), 0.8, // strength 0.4, // radius 0.85 // threshold ); composer.addPass(bloomPass); // Local procedural environment for better PBR response (no network) const pmrem = new THREE.PMREMGenerator(renderer); const roomEnv = new RoomEnvironment(); scene.environment = pmrem.fromScene(roomEnv).texture; pmrem.dispose(); roomEnv.dispose(); scene.environment = null; // This will make the renderer's clear color visible again return { scene, camera, renderer, composer, raycaster, mouse }; } export function setupLighting(scene, camera) { // Consistent Lighting Setup const ambientLight = new THREE.AmbientLight(0xffffff, 1); scene.add(ambientLight); const hemiLight = new THREE.HemisphereLight(0xffffff, 0x666666, 2); hemiLight.position.set(0, 20, 0); scene.add(hemiLight); const fillLight = new THREE.DirectionalLight(0xffffff, 1.8); fillLight.position.set(-12, 6, -8); scene.add(fillLight); const topLight = new THREE.DirectionalLight(0xffffff, 2); topLight.position.set(5, 15, 5); scene.add(topLight); const bottomLight = new THREE.DirectionalLight(0xffffff, 2.2); bottomLight.position.set(-3, -8, 3); scene.add(bottomLight); const leftLight = new THREE.DirectionalLight(0xffffff, 1.5); leftLight.position.set(-12, 2, 5); scene.add(leftLight); const rightLight = new THREE.DirectionalLight(0xffffff, 1.5); rightLight.position.set(12, 2, -5); scene.add(rightLight); const frontLight = new THREE.DirectionalLight(0xffffff, 1.2); frontLight.position.set(8, 4, 12); scene.add(frontLight); const backLight = new THREE.DirectionalLight(0xffffff, 1.2); backLight.position.set(-8, 4, -12); scene.add(backLight); const cameraLight = new THREE.PointLight(0xffffff, 0.8, 0, 3); camera.add(cameraLight); scene.add(camera); } export function setupControls(camera, renderer) { // Controls with zoom and pan disabled and camera constraints const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.25; controls.enableZoom = false; // Disable zoom controls.enablePan = false; // Disable panning // Add camera constraints to prevent extreme angles controls.maxPolarAngle = Math.PI * 0.8; // Prevent looking too far up controls.minPolarAngle = Math.PI * 0.2; // Prevent looking too far down console.log('Orbit controls initialized with camera constraints and pan disabled'); return controls; }