Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/demo #5

Merged
merged 7 commits into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
@@ -1,20 +0,0 @@
import { IVoxelMaterial } from '@aresrpg/aresrpg-engine'
import { Color } from 'three'

enum EVoxelType {
ROCK,
GRASS,
SNOW,
WATER,
SAND,
}

const VOXEL_TYPE_COLORS: Record<EVoxelType, IVoxelMaterial> = [
{ color: new Color('#ABABAB') },
{ color: new Color('#00B920') },
{ color: new Color('#E5E5E5') },
{ color: new Color('#0055E2') },
{ color: new Color('#DCBE28') },
]

export { EVoxelType, VOXEL_TYPE_COLORS }
11 changes: 11 additions & 0 deletions src/common/defaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { VoxelType } from './types'

const DEFAULT_VOXEL_TYPES_MAPPING = (height: number) => {
if (height < 10) return VoxelType.WATER
else if (height < 20) return VoxelType.SAND
else if (height < 60) return VoxelType.GRASS
else if (height < 100) return VoxelType.ROCK
return VoxelType.SNOW
}

export { DEFAULT_VOXEL_TYPES_MAPPING }
60 changes: 60 additions & 0 deletions src/common/stats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
export class ProcGenStats {
// eslint-disable-next-line no-use-before-define
static singleton: ProcGenStats
static get instance() {
ProcGenStats.singleton = ProcGenStats.singleton || new ProcGenStats()
// put in global scope for access from dev console
// window.aresrpg = {}
// window.aresrpg.procgen = {}
// window.aresrpg.procgen.stats = ProcGenStats.singleton.stats
return ProcGenStats.singleton
}

stats: any = {
noiseRange: {
min: 1,
max: 0,
anomalies: 0,
},
adjacentCount: {
0: 0,
1: 0,
2: 0,
3: 0,
4: 0,
5: 0,
6: 0,
},
worldGen: {
time: 0,
blocks: 0,
iterations: 0,
},
}

/**
* silently report noise anomalies
* @param noiseVal
*/
noiseAnomaly(noiseVal: number) {
const { noiseRange } = this.stats
noiseRange.min = noiseVal < noiseRange.min ? noiseVal : noiseRange.min
noiseRange.max = noiseVal > noiseRange.max ? noiseVal : noiseRange.max
noiseRange.anomalies++
}

adjacentNeighboursCount(adjCount: number) {
const { adjacentCount } = this.stats
adjacentCount[adjCount]++
}

get worldGen() {
return this.stats.worldGen
}

set worldGen(stats) {
this.stats.worldGen.time += stats.time || 0
this.stats.worldGen.blocks += stats.blocks || 0
this.stats.worldGen.iterations += stats.iterations || 0
}
}
20 changes: 20 additions & 0 deletions src/common/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { IVoxelMaterial } from '@aresrpg/aresrpg-engine'
import { Color } from 'three'

enum VoxelType {
ROCK,
GRASS,
SNOW,
WATER,
SAND,
}

const VOXEL_TYPE_COLORS: Record<VoxelType, IVoxelMaterial> = [
{ color: new Color('#ABABAB') },
{ color: new Color('#00B920') },
{ color: new Color('#E5E5E5') },
{ color: new Color('#0055E2') },
{ color: new Color('#DCBE28') },
]

export { VoxelType, VOXEL_TYPE_COLORS }
131 changes: 119 additions & 12 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Vector2 } from 'three'
import { Vector2, Vector3 } from 'three'

import { EVoxelType } from './constants'
import { ProcGenStats } from './stats'

/**
* Removing out of range values
Expand All @@ -9,10 +9,11 @@ import { EVoxelType } from './constants'
*/
const sanitiseNoise = (noiseVal: number) => {
let res = noiseVal
const isValidNoiseRange = !isNaN(noiseVal) && noiseVal >= 0 && noiseVal <= 1
if (!isValidNoiseRange) {
const invalidNoiseRange = isNaN(noiseVal) || noiseVal < 0 || noiseVal > 1
// correct and report noise anomaly
if (invalidNoiseRange) {
res = Math.round(noiseVal)
console.warn(`invalid noise value: ${noiseVal} corrected to ${res}`)
ProcGenStats.instance.noiseAnomaly(noiseVal)
}
return res
}
Expand All @@ -35,13 +36,119 @@ const interpolatePoints = (p1: Vector2, p2: Vector2, t: number) => {
const slope = range.x > 0 ? range.y / range.x : 0
return p1.y + slope * (t - p1.x)
}
enum NeighbourType {
xMyMzM,
xMyMz0,
xMyMzP,
xMy0zM,
xMy0z0,
xMy0zP,
xMyPzM,
xMyPz0,
xMyPzP,
x0yMzM,
x0yMz0,
x0yMzP,
x0y0zM,
x0y0zP,
x0yPzM,
x0yPz0,
x0yPzP,
xPyMzM,
xPyMz0,
xPyMzP,
xPy0zM,
xPy0z0,
xPy0zP,
xPyPzM,
xPyPz0,
xPyPzP,
}

const AjacentNeighbours = [
NeighbourType.xPy0z0,
NeighbourType.xMy0z0, // right, left
NeighbourType.x0yPz0,
NeighbourType.x0yMz0, // top, bottom
NeighbourType.x0y0zP,
NeighbourType.x0y0zM, // front, back
]

const getVoxelTypeFromHeight = (height: number) => {
if (height < 10) return EVoxelType.WATER
else if (height < 20) return EVoxelType.SAND
else if (height < 60) return EVoxelType.GRASS
else if (height < 100) return EVoxelType.ROCK
return EVoxelType.SNOW
/**
*
* @param pos point position to get neighbours from
* @param dir neighbour identifier
* @returns
*/
const getNeighbour = (pos: Vector3, dir: NeighbourType): Vector3 => {
switch (dir) {
case NeighbourType.xMyMzM:
return pos.clone().add(new Vector3(-1, -1, -1))
case NeighbourType.xMyMz0:
return pos.clone().add(new Vector3(-1, -1, 0))
case NeighbourType.xMyMzP:
return pos.clone().add(new Vector3(-1, -1, 1))
case NeighbourType.xMy0zM:
return pos.clone().add(new Vector3(-1, 0, -1))
case NeighbourType.xMy0z0:
return pos.clone().add(new Vector3(-1, 0, 0))
case NeighbourType.xMy0zP:
return pos.clone().add(new Vector3(-1, 0, 1))
case NeighbourType.xMyPzM:
return pos.clone().add(new Vector3(-1, 1, -1))
case NeighbourType.xMyPz0:
return pos.clone().add(new Vector3(-1, 1, 0))
case NeighbourType.xMyPzP:
return pos.clone().add(new Vector3(-1, 1, 1))
case NeighbourType.x0yMzM:
return pos.clone().add(new Vector3(0, -1, -1))
case NeighbourType.x0yMz0:
return pos.clone().add(new Vector3(0, -1, 0))
case NeighbourType.x0yMzP:
return pos.clone().add(new Vector3(0, -1, 1))
case NeighbourType.x0y0zM:
return pos.clone().add(new Vector3(0, 0, -1))
case NeighbourType.x0y0zP:
return pos.clone().add(new Vector3(0, 0, 1))
case NeighbourType.x0yPzM:
return pos.clone().add(new Vector3(0, 1, -1))
case NeighbourType.x0yPz0:
return pos.clone().add(new Vector3(0, 1, 0))
case NeighbourType.x0yPzP:
return pos.clone().add(new Vector3(0, 1, 1))
case NeighbourType.xPyMzM:
return pos.clone().add(new Vector3(1, -1, -1))
case NeighbourType.xPyMz0:
return pos.clone().add(new Vector3(1, -1, 0))
case NeighbourType.xPyMzP:
return pos.clone().add(new Vector3(1, -1, 1))
case NeighbourType.xPy0zM:
return pos.clone().add(new Vector3(1, 0, -1))
case NeighbourType.xPy0z0:
return pos.clone().add(new Vector3(1, 0, 0))
case NeighbourType.xPy0zP:
return pos.clone().add(new Vector3(1, 0, 1))
case NeighbourType.xPyPzM:
return pos.clone().add(new Vector3(1, 1, -1))
case NeighbourType.xPyPz0:
return pos.clone().add(new Vector3(1, 1, 0))
case NeighbourType.xPyPzP:
return pos.clone().add(new Vector3(1, 1, 1))
}
}

const getAllNeighbours = (pos: Vector3): Vector3[] => {
const neighbours = Object.values(NeighbourType)
.filter(v => !isNaN(Number(v)))
.map(type => getNeighbour(pos, type as number))
return neighbours
}

export { sanitiseNoise, round2, interpolatePoints, getVoxelTypeFromHeight }
export {
sanitiseNoise,
round2,
interpolatePoints,
getAllNeighbours,
AjacentNeighbours,
getNeighbour,
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ export { WorldGenerator } from './procgen/WorldGen'
export { SimplexNoiseSampler } from './procgen/NoiseSampler'
export { HeightProfiler } from './procgen/HeightProfiler'
export { BlendMode, ProcGenLayer, GenLayer } from './procgen/ProcGenLayer'
export { ProcGenStats } from './common/stats'
export { VoxelType } from './common/types'
40 changes: 6 additions & 34 deletions src/procgen/ProcGenLayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,8 @@ export class ProcGenLayer extends GenLayer {

eval(input: InputType) {
const { noiseSampler } = this
const statsRange = this.stats.range
const { min, max } = statsRange
const spread = this.config.spreading
const rawVal = noiseSampler.eval(input.clone().multiplyScalar(NOISE_SCALE))
if (rawVal < min) statsRange.min = rawVal
else if (rawVal > max) statsRange.max = rawVal
const finalVal = this.samplerProfile.apply(
(rawVal - 0.5) * 2 ** spread + 0.5,
)
Expand All @@ -189,7 +185,6 @@ export class ProcGenLayer extends GenLayer {
layers.forEach(layer => {
val = layer.eval(input.clone())
vals = layer.compositor(vals, val / 255, layer.params.blending.weight)
// vals= layer.noisePanel.compositor(vals, val / 255, layer.noisePanel.config.blend_weight);
})
return vals * 255
}
Expand Down Expand Up @@ -236,13 +231,13 @@ export class ProcGenLayer extends GenLayer {
}

static fromJsonConfig(jsonConf: any) {
console.log(jsonConf)
const layers: ProcGenLayer[] = jsonConf.noise_panels.map(
(panel: any, i: number) => {
// console.log(jsonConf)
const layers: ProcGenLayer[] = jsonConf.procLayers.map(
(layerCfg: any, i: number) => {
const noiseSeed = `layer#${i}_seed`
const layer = new ProcGenLayer(noiseSeed, panel.spline)
layer.applyConfig(panel)
return layer
const procLayer = new ProcGenLayer(noiseSeed, layerCfg.spline)
procLayer.applyConfig(layerCfg)
return procLayer
},
)
layers.reduce((prev, curr) => {
Expand All @@ -252,26 +247,3 @@ export class ProcGenLayer extends GenLayer {
return layers[0]
}
}

// const DEFAULT_PROFILE: HeightProfiler = new HeightProfiler(CurvePresets.)

// GenLayersChain
// GenLayersChain.compose(firstLayer)

/**
* must be inserted in LayersCombinator to be used
*/
// interface GenSourceLayer {

// }

// export class ProcGenSourceLayer implements GenSourceLayer {

// }
/**
* Layer composition/blending
* Combining several SourceLayer to aggregate and mix their values
*/
// export class LayersCombinator {

// }
Loading