Low-poly Island

Generate a low poly 3D ISLAND with a noise algo by notchris

by notchris

HTML

<script>
if (!window) {
  var window = {}
} else if (!module) {
  var module = {}
}

window.crusoe = module.exports = (function () {
  function getColor (n, colors) {
    if (n > 0.9) {
      return colors.A
    } else if (n > 0.8) {
      return colors.B
    } else if (n > 0.7) {
      return colors.C
    } else if (n > 0.5) {
      return colors.D
    } else if (n > 0) {
      return colors.E
    } else if (n > -0.1) {
      return colors.F
    } else if (n > -0.15) {
      return colors.G
    } else if (n > -0.2) {
      return colors.H
    } else if (n > -0.25) {
      return colors.I
    } else if (n > -0.3) {
      return colors.J
    } else if (n > -0.35) {
      return colors.K
    } else {
      return colors.L
    }
  }

  var defaultOptions = {
    width: 100,
    height: 100,
    noiseReduction: 10,
    seed: 0,
    size: 1,
    elevation: 3,
    lakeSize: 3,
    curve: 1
  }

  function generateMap (options) {
    options = Object.assign({}, defaultOptions, options)

    var width = options.width
    var height = options.height
    var seed = options.seed
    var size = options.size - 1
    var curve = options.curve * 2
    var elevation = -2 + options.elevation
    var lakeSize = options.lakeSize
    var scale = options.noiseReduction
    var scaleHalf = scale / 2
    var scale2 = scale * 2

    var islandW = width * 0.5
    var islandH = height * 0.5
    var diagonalHalf = Math.sqrt(width * width + height * height)

    noise.seed(seed)

    var data = []

    for (var x = 0; x < width; x++) {
      data[x] = []

      for (var y = 0; y < height; y++) {
        var dist = Math.sqrt(Math.pow((x - width / 2) / islandW, 2) + Math.pow((y - height / 2) / islandH, 2))
        var islandFactor = (dist < diagonalHalf ? Math.cos(dist * Math.PI / 2) + size : -10) * 4 * curve

        var terrainFactor = (noise.simplex2(x / scale, y / scale) + noise.perlin2(x / scaleHalf, y / scaleHalf)) / 3
        var lakeFactor = islandFactor > 0 ? noise.perlin2(x /...

CSS

body {
	background-color: #000;
	margin: 0px;
	overflow: hidden;
}
#canvas {
  position: absolute;
  top: 0;
  left: 0;
  image-rendering: pixelated;
}

JavaScript

import * as THREE from "https://cdn.skypack.dev/[email protected]";
import {
  OrbitControls
} from "https://cdn.skypack.dev/[email protected]/examples/jsm/controls/OrbitControls";

const options = {
  sharpness: 1,
  size: 0.8,
  resolution: 0.3,
  noise: 1.0,
  elevation: 2.0,
  lakeSize: 2.0,
  curve: 2.0
}

let mesh, renderer, scene, camera, controls;

function map(val, smin, smax, emin, emax) {
  const t = (val - smin) / (smax - smin)
  return (emax - emin) * t + emin
}

const canvas = document.getElementById('canvas')
canvas.width = 25
canvas.height = 25
const ctx = canvas.getContext('2d')

function generateTexture() {

  const rendered = crusoe.renderMap(crusoe.generateMap({
    seed: Date.now(),
    width: 120 * options.resolution,
    height: 120 * options.resolution,
    size: parseFloat(options.size, 10),
    noiseReduction: options.noise,
    elevation: options.elevation,
    lakeSize: options.lakeSize,
    curve: options.curve
  }), {
    A: '#EEEEEE',
    B: '#DDDDDD',
    C: '#CCCCCC',
    D: '#BBBBBB',
    E: '#AAAAAA',
    F: '#1d2e5b',
    G: '#1d2e5b',
    H: '#1d2e5b',
    I: '#1d2e5b',
    J: '#1d2e5b',
    K: '#1d2e5b',
    L: '#1d2e5b'
  })

  for (let x = 0; x < rendered.width; x++) {
    for (let y = 0; y < rendered.height; y++) {
      ctx.fillStyle = rendered.colors[x][y]
      const gridSize = (canvas.width / (120 * options.resolution))
      ctx.fillRect(x * gridSize, y * gridSize, gridSize, gridSize)
    }
  }
  return ctx.getImageData(0, 0, canvas.width, canvas.height)
}

init();
animate();

function init() {
  let data = generateTexture();
  // renderer
  renderer = new THREE.WebGLRenderer({
    antialias: true
  })
  renderer.setSize(window.innerWidth, window.innerHeight)
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.shadowMap.enabled = true
  renderer.shadowMap.type = THREE.PCFSoftShadowMap
  document.body.appendChild(renderer.domElement)

  // scene
  scene = new THREE.Scene();

  // camera
  const aspect =...