aether-shards/src/grid/VoxelManager.js

93 lines
2.7 KiB
JavaScript
Raw Normal View History

2025-12-16 23:52:58 +00:00
import * as THREE from "three";
/**
* VoxelManager.js
* Handles the Three.js rendering of the VoxelGrid.
* Uses InstancedMesh for performance (1 draw call for 10,000 blocks).
*/
export class VoxelManager {
constructor(grid, scene) {
this.grid = grid;
this.scene = scene;
this.mesh = null;
// Define Material Palette (ID -> Color)
this.palette = [
null, // 0: Air (Invisible)
new THREE.Color(0x888888), // 1: Stone (Grey)
new THREE.Color(0x8b4513), // 2: Dirt (Brown)
new THREE.Color(0x228b22), // 3: Grass (Green)
new THREE.Color(0x00f0ff), // 4: Aether Crystal (Cyan)
];
this.init();
}
init() {
// Create geometry once
const geometry = new THREE.BoxGeometry(1, 1, 1);
// Basic material allows for coloring individual instances
const material = new THREE.MeshLambertMaterial({ color: 0xffffff });
// Calculate max capacity based on grid size
const count = this.grid.width * this.grid.height * this.grid.depth;
// Create the InstancedMesh
this.mesh = new THREE.InstancedMesh(geometry, material, count);
this.mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
// Add to scene
this.scene.add(this.mesh);
}
/**
* Rebuilds the visual mesh based on the grid data.
* Call this in the game loop if grid.dirty is true.
*/
update() {
if (!this.grid.dirty) return;
let instanceId = 0;
const dummy = new THREE.Object3D();
for (let y = 0; y < this.grid.height; y++) {
for (let z = 0; z < this.grid.depth; z++) {
for (let x = 0; x < this.grid.width; x++) {
const typeId = this.grid.getVoxel(x, y, z);
if (typeId !== 0) {
// Position the dummy object
dummy.position.set(x, y, z);
dummy.updateMatrix();
// Update the instance matrix
this.mesh.setMatrixAt(instanceId, dummy.matrix);
// Update the instance color based on ID
const color = this.palette[typeId] || new THREE.Color(0xff00ff); // Magenta = Error
this.mesh.setColorAt(instanceId, color);
instanceId++;
}
}
}
}
// Hide unused instances by scaling them to zero (or moving them to infinity)
// For simplicity in this prototype, we define count as max possible,
// but in production, we would manage the count property more dynamically.
this.mesh.count = instanceId;
this.mesh.instanceMatrix.needsUpdate = true;
// instanceColor is lazy-created by Three.js only when setColorAt is called.
// If the grid is empty, instanceColor might be null.
if (this.mesh.instanceColor) {
this.mesh.instanceColor.needsUpdate = true;
}
this.grid.dirty = false;
}
}