3dexperiments/src/engine/components/terrain/heightmap.js

73 lines
1.8 KiB
JavaScript

import OpenSimplexNoise from 'open-simplex-noise'
import { vec3 } from 'gl-matrix'
import Resource from '../../resource'
class HeightMap {
constructor (size) {
this.size = size
}
static async fromFile (file, amplitude) {
let img = await Resource.loadImage(file)
if (img.width / img.height !== 1) throw new Error('Height Map needs to be of 1:1 aspect ratio.')
let hmap = new HeightMap(img.width)
let sampler = Resource.imageToSampler(img)
for (let x = 0; x < img.width; x++) {
for (let y = 0; y < img.width; y++) {
hmap['h' + x + ';' + y] = (sampler(x, y)[0] / 255 * 2 - 1) * amplitude
}
}
sampler = null
return hmap
}
getHeight (x, y) {
if (x > this.size || y > this.size || x < 0 || y < 0) return 0
if (!this['h' + x + ';' + y]) return 0
return this['h' + x + ';' + y]
}
getNormal (x, y) {
let hL = this.getHeight(x - 1, y)
let hR = this.getHeight(x + 1, y)
let hD = this.getHeight(x, y - 1)
let hU = this.getHeight(x, y + 1)
let normal = vec3.fromValues(hL - hR, 2.0, hD - hU)
vec3.normalize(normal, normal)
return normal
}
}
class SimplexHeightMap extends HeightMap {
constructor (offsetX, offsetY, size, seed) {
super(size)
this.ix = offsetX
this.iy = offsetY
this.seed = seed
this.osn = new OpenSimplexNoise(seed)
}
getNoise (relX, relY) {
let x = ((this.ix * this.size) + relX) / this.size - 0.5
let y = ((this.iy * this.size) + relY) / this.size - 0.5
let total = this.osn.noise2D(2 * x, 2 * y) +
0.5 * this.osn.noise2D(4 * x, 4 * y) +
0.25 * this.osn.noise2D(2 * x, 2 * y)
total *= 10
return total
}
getHeight (x, y) {
return this.getNoise(x, y)
}
}
export { HeightMap, SimplexHeightMap }