|
|
| class SceneManager { |
| constructor(config = {}) { |
| |
| this.scene = new THREE.Scene(); |
| this.scene.background = new THREE.Color(config.backgroundColor || 0x0a0e27); |
| this.scene.fog = new THREE.Fog(config.backgroundColor || 0x0a0e27, 100, 1000); |
|
|
| |
| this.camera = new THREE.PerspectiveCamera( |
| 75, |
| window.innerWidth / window.innerHeight, |
| 0.1, |
| 1000 |
| ); |
| this.camera.position.set(0, 0, config.cameraDistance || 15); |
|
|
| |
| this.renderer = new THREE.WebGLRenderer({ |
| canvas: document.getElementById('canvas'), |
| antialias: true, |
| alpha: true |
| }); |
| this.renderer.setSize(window.innerWidth, window.innerHeight); |
| this.renderer.setPixelRatio(window.devicePixelRatio); |
| this.renderer.shadowMap.enabled = true; |
|
|
| |
| this.setupLighting(); |
|
|
| |
| this.sphereManager = new SphereManager(this.scene); |
| this.connectionManager = new ConnectionManager(this.scene); |
|
|
| |
| this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement); |
| this.controls.enableDamping = true; |
| this.controls.dampingFactor = 0.05; |
| this.controls.screenSpacePanning = false; |
| this.controls.minDistance = 5; |
| this.controls.maxDistance = 500; |
| this.controls.maxPolarAngle = Math.PI; |
|
|
| |
| this.initialCameraPosition = this.camera.position.clone(); |
| this.initialControlsTarget = new THREE.Vector3(0, 0, 0); |
|
|
| |
| window.addEventListener('resize', () => this.onWindowResize()); |
|
|
| |
| const resetCameraButton = document.getElementById('resetCameraButton'); |
| if (resetCameraButton) { |
| resetCameraButton.addEventListener('click', () => { |
| this.resetCameraView(); |
| }); |
| } |
|
|
| |
| this.animate(); |
|
|
| console.log('✓ Scene3D initialized'); |
| } |
|
|
| |
| |
| |
| setupLighting() { |
| const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); |
| this.scene.add(ambientLight); |
|
|
| |
| const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); |
| directionalLight.position.set(10, 10, 10); |
| directionalLight.castShadow = true; |
| directionalLight.shadow.mapSize.width = 2048; |
| directionalLight.shadow.mapSize.height = 2048; |
| this.scene.add(directionalLight); |
|
|
| |
| const pointLight1 = new THREE.PointLight(0xff0080, 0.3, 100); |
| pointLight1.position.set(-10, 10, 10); |
| this.scene.add(pointLight1); |
|
|
| const pointLight2 = new THREE.PointLight(0x0080ff, 0.3, 100); |
| pointLight2.position.set(10, -10, 10); |
| this.scene.add(pointLight2); |
| } |
|
|
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| loadFromJSON(jsonConfig) { |
| |
| this.sphereManager.clearAll(); |
| this.connectionManager.clearAll(); |
|
|
| |
| if (jsonConfig.spheres && Array.isArray(jsonConfig.spheres)) { |
| jsonConfig.spheres.forEach(sphereConfig => { |
| const position = new THREE.Vector3( |
| sphereConfig.position?.x || 0, |
| sphereConfig.position?.y || 0, |
| sphereConfig.position?.z || 0 |
| ); |
|
|
| this.sphereManager.addSphere(sphereConfig.name, { |
| radius: sphereConfig.radius || 1, |
| color: sphereConfig.color || '#ff0000', |
| position: position, |
| opacity: sphereConfig.opacity || 1 |
| }); |
| }); |
| } |
|
|
| |
| if (jsonConfig.connections && Array.isArray(jsonConfig.connections)) { |
| jsonConfig.connections.forEach(connConfig => { |
| const fromSphere = this.sphereManager.getSphere(connConfig.from); |
| const toSphere = this.sphereManager.getSphere(connConfig.to); |
|
|
| if (fromSphere && toSphere) { |
| this.connectionManager.addConnection( |
| connConfig.id || `conn_${connConfig.from}_${connConfig.to}`, |
| fromSphere.position, |
| toSphere.position, |
| { |
| color: connConfig.color || '#00ff00', |
| lineWidth: connConfig.lineWidth || 2, |
| fromSphere: connConfig.from, |
| toSphere: connConfig.to |
| } |
| ); |
| } else { |
| console.warn(`Connection ${connConfig.id}: sphere(s) not found`); |
| } |
| }); |
| } |
|
|
| console.log('✓ Scene loaded from JSON'); |
| } |
|
|
| |
| |
| |
| onWindowResize() { |
| this.camera.aspect = window.innerWidth / window.innerHeight; |
| this.camera.updateProjectionMatrix(); |
| this.renderer.setSize(window.innerWidth, window.innerHeight); |
| } |
|
|
| resetCameraView() { |
| |
| const wasDamping = this.controls.enableDamping; |
| this.controls.enableDamping = false; |
|
|
| |
| this.camera.position.copy(this.initialCameraPosition); |
| this.controls.target.copy(this.initialControlsTarget); |
|
|
| |
| this.controls.reset(); |
|
|
| |
| this.controls.update(); |
|
|
| |
| this.controls.enableDamping = wasDamping; |
|
|
| console.log('✓ Camera view reset'); |
| } |
|
|
| |
| |
| |
| animate() { |
| requestAnimationFrame(() => this.animate()); |
|
|
| |
| this.controls.update(); |
|
|
| |
| this.connectionManager.getAllConnections().forEach(conn => { |
| const fromSphere = this.sphereManager.getSphere(conn.fromSphere); |
| const toSphere = this.sphereManager.getSphere(conn.toSphere); |
|
|
| if (fromSphere && toSphere) { |
| this.connectionManager.updateConnectionPositions( |
| conn.id, |
| fromSphere.position, |
| toSphere.position |
| ); |
| } |
| }); |
|
|
| this.renderer.render(this.scene, this.camera); |
| } |
| } |