From fed6a268827b984d21b1d45057e05bed56d41dab Mon Sep 17 00:00:00 2001 From: a dinosaur Date: Thu, 5 Sep 2024 22:32:30 +1000 Subject: [PATCH] technicolour icecream hellscape terrain --- Sources/Voxelotl/Game.swift | 4 +- .../Generator/StandardWorldGenerator.swift | 42 +++++++++------- .../Voxelotl/Generator/WorldGenerator.swift | 2 +- Sources/Voxelotl/Noise/LayeredNoise.swift | 48 +++++++++++++++++++ Sources/Voxelotl/Noise/SimplexNoise.swift | 39 +++++++-------- Sources/Voxelotl/World.swift | 4 +- 6 files changed, 97 insertions(+), 42 deletions(-) diff --git a/Sources/Voxelotl/Game.swift b/Sources/Voxelotl/Game.swift index d6e3843..0cec992 100644 --- a/Sources/Voxelotl/Game.swift +++ b/Sources/Voxelotl/Game.swift @@ -24,7 +24,7 @@ class Game: GameDelegate { var camera = Camera(fov: 60, size: .one, range: 0.06...900) var player = Player() var projection: matrix_float4x4 = .identity - var world = World() + var world = World(generator: StandardWorldGenerator()) var cubeMesh: RendererMesh? var renderChunks = [SIMD3: RendererMesh]() var chunkMeshGeneration: ChunkMeshGeneration! @@ -42,7 +42,7 @@ class Game: GameDelegate { } private func resetPlayer() { - self.player.position = .init(repeating: 0.5) + .up * Float(Chunk.size) + self.player.position = .init(repeating: 0.5) + .up * Float(Chunk.size) * 1.6 self.player.velocity = .zero self.player.rotation = .init(.pi, 0) } diff --git a/Sources/Voxelotl/Generator/StandardWorldGenerator.swift b/Sources/Voxelotl/Generator/StandardWorldGenerator.swift index 352cc9b..53b7ba1 100644 --- a/Sources/Voxelotl/Generator/StandardWorldGenerator.swift +++ b/Sources/Voxelotl/Generator/StandardWorldGenerator.swift @@ -1,5 +1,7 @@ struct StandardWorldGenerator: WorldGenerator { - var noise: ImprovedPerlin!, noise2: SimplexNoise! + private var heightNoise: LayeredNoiseAlt>! + private var terrainNoise: LayeredNoise>! + private var colorNoise: LayeredNoise>! public mutating func reset(seed: UInt64) { var random: any RandomProvider @@ -10,29 +12,33 @@ struct StandardWorldGenerator: WorldGenerator { random = PCG32Random(seed: initialState) #endif - self.noise = ImprovedPerlin(random: &random) - self.noise2 = SimplexNoise(random: &random) + self.heightNoise = .init(random: &random, octaves: 200, frequency: 0.0002, amplitude: 2) + self.terrainNoise = .init(random: &random, octaves: 10, frequency: 0.01, amplitude: 0.337) + self.colorNoise = .init(random: &random, octaves: 150, frequency: 0.00366, amplitude: 2) } public func makeChunk(id chunkID: SIMD3) -> Chunk { let chunkOrigin = chunkID &<< Chunk.shift var chunk = Chunk(position: chunkOrigin) - chunk.fill(allBy: { position in - let fpos = SIMD3(chunkOrigin &+ position) - let threshold: Float = 0.6 - let value = fpos.y / 16.0 - + self.noise.get(fpos * 0.05) * 1.1 - + self.noise.get(fpos * 0.10) * 0.5 - + self.noise.get(fpos * 0.30) * 0.23 - return if value < threshold { - .solid(.init( - hue: Float(180 + self.noise2.get(fpos * 0.05) * 180), - saturation: Float(0.5 + self.noise2.get(SIMD4(fpos * 0.05, 4)) * 0.5), - value: Float(0.5 + self.noise2.get(SIMD4(fpos * 0.05, 9)) * 0.5).lerp(0.5, 1)).linear) - } else { - .air + for z in 0..(chunkOrigin.xz &+ SIMD2(x, z))) + for y in 0..(chunkOrigin &+ ipos) + let height = fpos.y / 64.0 + height + let value = height + self.terrainNoise.get(fpos) + let block: BlockType = if value < 0 { + .solid(.init( + hue: Float(180 + self.colorNoise.get(fpos) * 180), + saturation: 0.7, value: 0.9).linear) + } else { + .air + } + chunk.setBlock(internal: ipos, type: block) + } } - }) + } return chunk } } diff --git a/Sources/Voxelotl/Generator/WorldGenerator.swift b/Sources/Voxelotl/Generator/WorldGenerator.swift index 69c754d..232f237 100644 --- a/Sources/Voxelotl/Generator/WorldGenerator.swift +++ b/Sources/Voxelotl/Generator/WorldGenerator.swift @@ -1,4 +1,4 @@ -protocol WorldGenerator { +public protocol WorldGenerator { mutating func reset(seed: UInt64) func makeChunk(id: SIMD3) -> Chunk } diff --git a/Sources/Voxelotl/Noise/LayeredNoise.swift b/Sources/Voxelotl/Noise/LayeredNoise.swift index d2f6ce5..5ddee24 100644 --- a/Sources/Voxelotl/Noise/LayeredNoise.swift +++ b/Sources/Voxelotl/Noise/LayeredNoise.swift @@ -58,3 +58,51 @@ public extension LayeredNoise where Generator: CoherentNoise4D { $0 + $1 } * self._amplitudeAdjusted } } + +//MARK: - Experimental + +public struct LayeredNoiseAlt { + public typealias Scalar = Generator.Scalar + + public let octaves: Int + public let frequency: Scalar + public let amplitude: Scalar + + private let _generator: Generator + private let _amplitudeAdjusted: Scalar + +} + +public extension LayeredNoiseAlt where Generator: CoherentNoiseRandomInit { + init(random: inout Random, octaves: Int, frequency: Scalar, amplitude: Scalar = 1) { + self.octaves = octaves + self.frequency = frequency + self.amplitude = amplitude + self._generator = Generator(random: &random) + self._amplitudeAdjusted = amplitude / 2 + } +} + +public extension LayeredNoiseAlt where Generator: CoherentNoise3D & CoherentNoise2D { + func get(_ point: SIMD2) -> Scalar { + let layerOffset: Int = 1 + return (1..) -> Scalar { + let layerOffset: Int = 1 + return (1..: CoherentNoise2D, CoherentNoise3D, CoherentNoise4D, CoherentNoiseRandomInit, CoherentNoiseTableInit { private let p: [Int16], pMod12: [Int16] - private let grad3: [SIMD3] = [ - .init(1, 1, 0), .init(-1, 1, 0), .init(1, -1, 0), .init(-1, -1, 0), - .init(1, 0, 1), .init(-1, 0, 1), .init(1, 0, -1), .init(-1, 0, -1), - .init(0, 1, 1), .init( 0, -1, 1), .init(0, 1, -1), .init( 0, -1, -1) - ] - private let grad4: [SIMD4] = [ - .init( 0, 1, 1, 1), .init( 0, 1, 1, -1), .init( 0, 1, -1, 1), .init( 0, 1, -1, -1), - .init( 0, -1, 1, 1), .init( 0, -1, 1, -1), .init( 0, -1, -1, 1), .init( 0, -1, -1, -1), - .init( 1, 0, 1, 1), .init( 1, 0, 1, -1), .init( 1, 0, -1, 1), .init( 1, 0, -1, -1), - .init(-1, 0, 1, 1), .init(-1, 0, 1, -1), .init(-1, 0, -1, 1), .init(-1, 0, -1, -1), - .init( 1, 1, 0, 1), .init( 1, 1, 0, -1), .init( 1, -1, 0, 1), .init( 1, -1, 0, -1), - .init(-1, 1, 0, 1), .init(-1, 1, 0, -1), .init(-1, -1, 0, 1), .init(-1, -1, 0, -1), - .init( 1, 1, 1, 0), .init( 1, 1, -1, 0), .init( 1, -1, 1, 0), .init( 1, -1, -1, 0), - .init(-1, 1, 1, 0), .init(-1, 1, -1, 0), .init(-1, -1, 1, 0), .init(-1, -1, -1, 0) - ] - public init(permutation: [Int16]) { assert(permutation.count == 0x100) self.p = permutation @@ -58,7 +42,7 @@ public struct SimplexNoise: CoherentNo return 0 } else { t *= t - return t * t * self.grad3[gradID].xy.dot(corner) + return t * t * SIMD2(grad3[gradID].xy).dot(corner) } } let noise0 = cornerContribution(corner0, gradIndex0) @@ -125,7 +109,7 @@ public struct SimplexNoise: CoherentNo return 0 } else { t *= t - return t * t * self.grad3[gradID].dot(corner) + return t * t * SIMD3(grad3[gradID]).dot(corner) } } let noise0 = cornerContribution(corner0, gradCorner0) @@ -197,7 +181,7 @@ public struct SimplexNoise: CoherentNo return 0 } else { t *= t - return t * t * self.grad4[gradID].dot(corner) + return t * t * SIMD4(grad4[gradID]).dot(corner) } } let noise0 = cornerContribution(corner0, gradIndex0) @@ -212,3 +196,20 @@ public struct SimplexNoise: CoherentNo @inline(__always) fileprivate func perm(_ idx: Int) -> Int { Int(self.p[idx & 0xFF]) } @inline(__always) fileprivate func permMod12(_ idx: Int) -> Int { Int(self.pMod12[idx & 0xFF]) } } + +fileprivate let grad3: [SIMD3] = [ + .init(1, 1, 0), .init(-1, 1, 0), .init(1, -1, 0), .init(-1, -1, 0), + .init(1, 0, 1), .init(-1, 0, 1), .init(1, 0, -1), .init(-1, 0, -1), + .init(0, 1, 1), .init( 0, -1, 1), .init(0, 1, -1), .init( 0, -1, -1) +] + +fileprivate let grad4: [SIMD4] = [ + .init( 0, 1, 1, 1), .init( 0, 1, 1, -1), .init( 0, 1, -1, 1), .init( 0, 1, -1, -1), + .init( 0, -1, 1, 1), .init( 0, -1, 1, -1), .init( 0, -1, -1, 1), .init( 0, -1, -1, -1), + .init( 1, 0, 1, 1), .init( 1, 0, 1, -1), .init( 1, 0, -1, 1), .init( 1, 0, -1, -1), + .init(-1, 0, 1, 1), .init(-1, 0, 1, -1), .init(-1, 0, -1, 1), .init(-1, 0, -1, -1), + .init( 1, 1, 0, 1), .init( 1, 1, 0, -1), .init( 1, -1, 0, 1), .init( 1, -1, 0, -1), + .init(-1, 1, 0, 1), .init(-1, 1, 0, -1), .init(-1, -1, 0, 1), .init(-1, -1, 0, -1), + .init( 1, 1, 1, 0), .init( 1, 1, -1, 0), .init( 1, -1, 1, 0), .init( 1, -1, -1, 0), + .init(-1, 1, 1, 0), .init(-1, 1, -1, 0), .init(-1, -1, 1, 0), .init(-1, -1, -1, 0) +] diff --git a/Sources/Voxelotl/World.swift b/Sources/Voxelotl/World.swift index 27ac492..40687a5 100644 --- a/Sources/Voxelotl/World.swift +++ b/Sources/Voxelotl/World.swift @@ -12,10 +12,10 @@ public class World { private var _generator: any WorldGenerator private var _chunkGeneration: ChunkGeneration - public init() { + public init(generator: any WorldGenerator) { self._chunks = [:] self._chunkDamage = [] - self._generator = TerrorTowerGenerator() + self._generator = generator self._chunkGeneration = ChunkGeneration(queue: .global(qos: .userInitiated)) self._chunkGeneration.world = self }