Source: view/SceneEnvironment.js

import * as THREE from "three";
import { ResourceNames } from "../model/Utils/Resources/ResourcesNames";
import * as EnvView from "./environment/EnvView.js";
/**
 * Environment class to manage and set up the 3D environment in the simulation.
 * Handles setting up textures, lights, floor, surface, and other elements.
 *
 * @class
 */
class SceneEnvironment {
  /**
   * Creates an instance of Environment.
   *
   * @param {Simulator} simulator - The simulator instance that manages the entire simulation.
   * @constructor
   */
  constructor(simulator) {
    this.simulator = simulator;
    this.scene = this.simulator.scene;
    this.resources = this.simulator.resources;
    this.waterColor = "#999999";
    // this.setupTextures();
    // this.createSeaBottom();
    // this.createSeaSurface();
    // this.setupOceanEffect();
    this.setupLights();
    // this.addRandomObjects();
    EnvView.init(simulator);
    this.axesHelper = new THREE.AxesHelper(10000);
    this.showAxesHelper = false;
    this.setupAxesHelper();
  }
  /**
   * Sets up the axes helper for debugging purposes.
   * Allows toggling the visibility of the axes helper through the debug panel.
   *
   * @private
   */
  setupAxesHelper() {
    this.simulator.controlGUI.gui
      .add(this, "showAxesHelper")
      .name("Show Axes")
      .onChange((isShowed) => {
        if (isShowed) {
          this.scene.add(this.axesHelper);
        } else {
          this.scene.remove(this.axesHelper);
        }
      });
  }
  /**
   * Loads and sets up textures for the environment.
   *
   * @private
   */
  setupTextures() {
    this.dirtTexture = this.resources.getResource(
      ResourceNames.DirtColorTexture
    );
    this.dirtTexture.repeat.set(1000, 1000);
    this.dirtTexture.wrapS = THREE.MirroredRepeatWrapping;
    this.dirtTexture.wrapT = THREE.MirroredRepeatWrapping;
    this.stonesTexture = this.resources.getResource(
      ResourceNames.StonesColorTexture
    );
  }
  /**
   * Sets up the lights in the scene.
   * Includes ambient light, directional lights, point light, and spot light.
   *
   * @private
   */
  setupLights() {
    const color = new THREE.Color(this.waterColor);
    const ambientLight = new THREE.AmbientLight(color, 0.6);
    this.scene.add(ambientLight);
    const createDirectionalLight = (color, intensity, position) => {
      const light = new THREE.DirectionalLight(color, intensity);
      light.castShadow = true;
      light.shadow.mapSize.set(1024, 1024);
      light.shadow.camera.far = 5000;
      light.shadow.camera.left = -10;
      light.shadow.camera.top = 10;
      light.shadow.camera.right = 10;
      light.shadow.camera.bottom = -10;
      light.position.set(...position);
      return light;
    };
    const directionalLight1 = createDirectionalLight(color, 10, [10, 5, 10]);
    this.scene.add(directionalLight1);
    const directionalLight2 = createDirectionalLight(color, 10, [-10, 5, 10]);
    this.scene.add(directionalLight2);
    const pointLight = new THREE.PointLight(color, 10.5);
    pointLight.position.set(2, 3, 2);
    this.scene.add(pointLight);
    const spotLight = new THREE.SpotLight(color, 10.7);
    spotLight.position.set(15, 40, 35);
    spotLight.angle = Math.PI / 6;
    spotLight.penumbra = 0.1;
    spotLight.decay = 2;
    spotLight.distance = 200;
    spotLight.castShadow = true;
    spotLight.shadow.mapSize.set(2048, 2048);
    this.scene.add(spotLight);
  }
  /**
   * Creates the sea bottom plane with the appropriate texture and position.
   *
   * @private
   */
  createSeaBottom() {
    const seaBottomGeometry = new THREE.PlaneGeometry(20000, 20000);
    const seaBottomMaterial = new THREE.MeshBasicMaterial({
      map: this.dirtTexture,
      color: new THREE.Color(this.waterColor),
      side: THREE.DoubleSide,
    });
    const seaBottom = new THREE.Mesh(seaBottomGeometry, seaBottomMaterial);
    seaBottom.position.y = -1500; // Sea bottom below sea level
    seaBottom.receiveShadow = true;
    seaBottom.rotation.x = -Math.PI * 0.5;
    this.scene.add(seaBottom);
  }
  /**
   * Creates the sea surface plane with the appropriate texture and position.
   *
   * @private
   */
  createSeaSurface() {
    const seaSurfaceGeometry = new THREE.PlaneGeometry(20000, 20000);
    const seaSurfaceMaterial = new THREE.MeshBasicMaterial({
      map: this.dirtTexture,
      color: new THREE.Color(this.waterColor),
      side: THREE.DoubleSide,
    });
    const seaSurface = new THREE.Mesh(seaSurfaceGeometry, seaSurfaceMaterial);
    seaSurface.position.y = 0; // Sea level at origin
    seaSurface.rotation.x = -Math.PI * 0.5;
    this.scene.add(seaSurface);
  }
  /**
   * Sets up the ocean effect including background color and fog.
   *
   * @private
   */
  setupOceanEffect() {
    this.scene.background = new THREE.Color(this.waterColor);
    this.scene.fog = new THREE.Fog(this.waterColor, 1, 2000);
  }
  /**
   * Adds random objects to the scene for visual complexity.
   * Uses cone geometry and stone texture.
   *
   * @private
   */
  addRandomObjects() {
    const geometry = new THREE.ConeGeometry(10, 30, 4, 1);
    const material = new THREE.MeshBasicMaterial({
      color: "#AAAA00",
      map: this.stonesTexture,
    });
    for (let i = 0; i < 5000; i++) {
      const mesh = new THREE.Mesh(geometry, material);
      mesh.position.x = (Math.random() - 0.5) * 20000;
      mesh.position.y = Math.random() * -500; // Only place objects below sea level
      mesh.position.z = (Math.random() - 0.5) * 20000;
      this.scene.add(mesh);
    }
  }
}
export default SceneEnvironment;