Three.js - Voxel Geometry - Textures

by Lazaro Contreras

HTML

<canvas id="c"></canvas>

CSS

body {
  margin: 0;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}

JavaScript

// Three.js - Voxel Geometry - Textures
// from https://threejsfundamentals.org/threejs/threejs-voxel-geometry-culled-faces-with-textures.html

import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r110/build/three.module.js';
import {OrbitControls} from 'https://threejsfundamentals.org/threejs/resources/threejs/r110/examples/jsm/controls/OrbitControls.js';

class VoxelWorld {
  constructor(options) {
    this.cellSizeX = options.cellSizeX;
    this.cellSizeY = options.cellSizeY;
    this.cellSizeZ = options.cellSizeZ;
    this.tileSize = options.tileSize;
    this.tileTextureWidth = options.tileTextureWidth;
    this.tileTextureHeight = options.tileTextureHeight;
    const {cellSizeX, cellSizeY, cellSizeZ} = this;
    this.cellSliceSize = cellSizeX * cellSizeY;
    this.cell = new Uint8Array(cellSizeX * cellSizeY * cellSizeZ);
  }
  computeVoxelOffset(x, y, z) {
  	const {cellSizeX, cellSizeY, cellSizeZ, cellSliceSize} = this;
    const voxelX = THREE.Math.euclideanModulo(x, cellSizeX) | 0;
    const voxelY = THREE.Math.euclideanModulo(y, cellSizeY) | 0;
    const voxelZ = THREE.Math.euclideanModulo(z, cellSizeZ) | 0;
    return voxelY * cellSliceSize +
           voxelZ * cellSizeZ +
           voxelX;
  }
  getCellForVoxel(x, y, z) {
    const {cellSizeX, cellSizeY, cellSizeZ} = this;
    const cellX = Math.floor(x / cellSizeX);
    const cellY = Math.floor(y / cellSizeY);
    const cellZ = Math.floor(z / cellSizeZ);
    if (cellX !== 0 || cellY !== 0 || cellZ !== 0) {
      return null;
    }
    return this.cell;
  }
  setVoxel(x, y, z, v) {
    const cell = this.getCellForVoxel(x, y, z);
    if (!cell) {
      return;  // TODO: add a new cell?
    }
    const voxelOffset = this.computeVoxelOffset(x, y, z);
    cell[voxelOffset] = v;
  }
  getVoxel(x, y, z) {
    const cell = this.getCellForVoxel(x, y, z);
    if (!cell) {
      return 0;
    }
    const voxelOffset = this.computeVoxelOffset(x, y, z);
    return...