aether-shards/src/grid/VoxelManager.js

123 lines
3.5 KiB
JavaScript
Raw Normal View History

2025-12-16 23:52:58 +00:00
import * as THREE from "three";
/**
* VoxelManager.js
2025-12-17 19:26:42 +00:00
* Handles the Three.js rendering of the VoxelGrid data.
* Uses InstancedMesh for high performance.
2025-12-16 23:52:58 +00:00
*/
export class VoxelManager {
2025-12-17 19:26:42 +00:00
constructor(grid, scene, textureAtlas) {
2025-12-16 23:52:58 +00:00
this.grid = grid;
this.scene = scene;
2025-12-17 19:26:42 +00:00
this.textureAtlas = textureAtlas;
2025-12-16 23:52:58 +00:00
this.mesh = null;
2025-12-17 19:26:42 +00:00
this.needsUpdate = true;
// Define Materials per ID (Simplified for Prototype)
// In Phase 3, this will use the Texture Atlas UVs
this.material = new THREE.MeshStandardMaterial({ color: 0xffffff });
// Color Map: ID -> Hex
this.palette = {
1: new THREE.Color(0x555555), // Stone
2: new THREE.Color(0x3d2817), // Dirt
10: new THREE.Color(0x8b4513), // Wood (Destructible)
15: new THREE.Color(0x00ffff), // Crystal
};
2025-12-16 23:52:58 +00:00
}
2025-12-17 19:26:42 +00:00
/**
* Initializes the InstancedMesh based on grid size.
* Must be called after the grid is populated by WorldGen.
*/
2025-12-16 23:52:58 +00:00
init() {
2025-12-17 19:26:42 +00:00
if (this.mesh) {
this.scene.remove(this.mesh);
this.mesh.dispose();
}
2025-12-16 23:52:58 +00:00
2025-12-17 19:26:42 +00:00
const geometry = new THREE.BoxGeometry(1, 1, 1);
const count = this.grid.size.x * this.grid.size.y * this.grid.size.z;
2025-12-16 23:52:58 +00:00
2025-12-17 19:26:42 +00:00
this.mesh = new THREE.InstancedMesh(geometry, this.material, count);
this.mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage); // Allow updates
2025-12-16 23:52:58 +00:00
this.scene.add(this.mesh);
2025-12-17 19:26:42 +00:00
this.update();
2025-12-16 23:52:58 +00:00
}
/**
2025-12-17 19:26:42 +00:00
* Re-calculates positions for all voxels.
* Call this when terrain is destroyed or modified.
2025-12-16 23:52:58 +00:00
*/
update() {
2025-12-17 19:26:42 +00:00
if (!this.mesh) return;
2025-12-16 23:52:58 +00:00
let instanceId = 0;
const dummy = new THREE.Object3D();
2025-12-17 19:26:42 +00:00
for (let y = 0; y < this.grid.size.y; y++) {
for (let z = 0; z < this.grid.size.z; z++) {
for (let x = 0; x < this.grid.size.x; x++) {
const cellId = this.grid.getCell(x, y, z);
2025-12-16 23:52:58 +00:00
2025-12-17 19:26:42 +00:00
if (cellId !== 0) {
// Position the cube
2025-12-16 23:52:58 +00:00
dummy.position.set(x, y, z);
dummy.updateMatrix();
2025-12-17 19:26:42 +00:00
// Apply Transform
2025-12-16 23:52:58 +00:00
this.mesh.setMatrixAt(instanceId, dummy.matrix);
2025-12-17 19:26:42 +00:00
// Apply Color based on ID
const color = this.palette[cellId] || new THREE.Color(0xff00ff); // Magenta = Error
2025-12-16 23:52:58 +00:00
this.mesh.setColorAt(instanceId, color);
2025-12-17 19:26:42 +00:00
} else {
// Hide Air voxels by scaling to 0
dummy.position.set(0, 0, 0);
dummy.scale.set(0, 0, 0);
dummy.updateMatrix();
this.mesh.setMatrixAt(instanceId, dummy.matrix);
// Reset scale for next iteration
dummy.scale.set(1, 1, 1);
2025-12-16 23:52:58 +00:00
}
2025-12-17 19:26:42 +00:00
instanceId++;
2025-12-16 23:52:58 +00:00
}
}
}
this.mesh.instanceMatrix.needsUpdate = true;
2025-12-17 19:26:42 +00:00
if (this.mesh.instanceColor) this.mesh.instanceColor.needsUpdate = true;
}
2025-12-16 23:52:58 +00:00
2025-12-17 19:26:42 +00:00
/**
* Efficiently updates a single voxel without rebuilding the whole mesh.
* Use this for 'destroyVoxel' events.
*/
updateVoxel(x, y, z) {
// Calculate the specific index in the flat array
const index =
y * this.grid.size.x * this.grid.size.z + z * this.grid.size.x + x;
const cellId = this.grid.getCell(x, y, z);
const dummy = new THREE.Object3D();
if (cellId !== 0) {
dummy.position.set(x, y, z);
dummy.updateMatrix();
this.mesh.setMatrixAt(index, dummy.matrix);
const color = this.palette[cellId] || new THREE.Color(0xff00ff);
this.mesh.setColorAt(index, color);
} else {
// Hide it
dummy.scale.set(0, 0, 0);
dummy.updateMatrix();
this.mesh.setMatrixAt(index, dummy.matrix);
2025-12-16 23:52:58 +00:00
}
2025-12-17 19:26:42 +00:00
this.mesh.instanceMatrix.needsUpdate = true;
this.mesh.instanceColor.needsUpdate = true;
2025-12-16 23:52:58 +00:00
}
}