96 lines
2.6 KiB
JavaScript
96 lines
2.6 KiB
JavaScript
import * as THREE from 'three';
|
|
|
|
let scene, camera, renderer;
|
|
|
|
const _worldObjects = [];
|
|
|
|
/**
|
|
* @param {HTMLCanvasElement|null} existingCanvas — pass the saved canvas on
|
|
* re-init so Three.js reuses the same DOM element instead of creating a new one
|
|
*/
|
|
export function initWorld(existingCanvas) {
|
|
_worldObjects.length = 0;
|
|
|
|
scene = new THREE.Scene();
|
|
scene.background = new THREE.Color(0x000000);
|
|
scene.fog = new THREE.FogExp2(0x000000, 0.035);
|
|
|
|
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 500);
|
|
camera.position.set(0, 12, 28);
|
|
camera.lookAt(0, 0, 0);
|
|
|
|
renderer = new THREE.WebGLRenderer({
|
|
antialias: true,
|
|
canvas: existingCanvas || undefined,
|
|
});
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
|
|
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
|
|
|
if (!existingCanvas) {
|
|
document.body.prepend(renderer.domElement);
|
|
}
|
|
|
|
addLights(scene);
|
|
addGrid(scene);
|
|
|
|
return { scene, camera, renderer };
|
|
}
|
|
|
|
/**
|
|
* Dispose only world-owned geometries, materials, and the renderer.
|
|
* Agent and effect objects are disposed by their own modules before this runs.
|
|
*/
|
|
export function disposeWorld(renderer, _scene) {
|
|
for (const obj of _worldObjects) {
|
|
if (obj.geometry) obj.geometry.dispose();
|
|
if (obj.material) {
|
|
const mats = Array.isArray(obj.material) ? obj.material : [obj.material];
|
|
mats.forEach(m => {
|
|
if (m.map) m.map.dispose();
|
|
m.dispose();
|
|
});
|
|
}
|
|
}
|
|
_worldObjects.length = 0;
|
|
renderer.dispose();
|
|
}
|
|
|
|
function addLights(scene) {
|
|
const ambient = new THREE.AmbientLight(0x001a00, 0.6);
|
|
scene.add(ambient);
|
|
|
|
const point = new THREE.PointLight(0x00ff41, 2, 80);
|
|
point.position.set(0, 20, 0);
|
|
scene.add(point);
|
|
|
|
const fill = new THREE.DirectionalLight(0x003300, 0.4);
|
|
fill.position.set(-10, 10, 10);
|
|
scene.add(fill);
|
|
}
|
|
|
|
function addGrid(scene) {
|
|
const grid = new THREE.GridHelper(100, 40, 0x003300, 0x001a00);
|
|
grid.position.y = -0.01;
|
|
scene.add(grid);
|
|
_worldObjects.push(grid);
|
|
|
|
const planeGeo = new THREE.PlaneGeometry(100, 100);
|
|
const planeMat = new THREE.MeshBasicMaterial({
|
|
color: 0x000a00,
|
|
transparent: true,
|
|
opacity: 0.5,
|
|
});
|
|
const plane = new THREE.Mesh(planeGeo, planeMat);
|
|
plane.rotation.x = -Math.PI / 2;
|
|
plane.position.y = -0.02;
|
|
scene.add(plane);
|
|
_worldObjects.push(plane);
|
|
}
|
|
|
|
export function onWindowResize(camera, renderer) {
|
|
camera.aspect = window.innerWidth / window.innerHeight;
|
|
camera.updateProjectionMatrix();
|
|
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
}
|