mirror of
				https://github.com/GayPizzaSpecifications/voxelotl-engine.git
				synced 2025-11-04 02:59:37 +00:00 
			
		
		
		
	improved perlin basic blockgen
This commit is contained in:
		@ -20,6 +20,8 @@ add_executable(Voxelotl MACOSX_BUNDLE
 | 
			
		||||
  Random/Arc4Random.swift
 | 
			
		||||
  Random/PCG32Random.swift
 | 
			
		||||
  Random/Xoroshiro128.swift
 | 
			
		||||
  Random/PerlinNoiseGenerator.swift
 | 
			
		||||
  Random/RandomCollectionExtensions.swift
 | 
			
		||||
 | 
			
		||||
  # Resource classes
 | 
			
		||||
  NSImageLoader.swift
 | 
			
		||||
 | 
			
		||||
@ -43,9 +43,15 @@ public struct Chunk {
 | 
			
		||||
    blocks[position.x + position.y * Self.yStride + position.z * Self.zStride].type = type
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  mutating func fill(allBy calculation: () -> BlockType) {
 | 
			
		||||
    blocks.indices.forEach { i in
 | 
			
		||||
      blocks[i].type = calculation()
 | 
			
		||||
  mutating func fill(allBy calculation: (_ position: SIMD3<Int>) -> BlockType) {
 | 
			
		||||
    var i = 0
 | 
			
		||||
    for x in 0..<Self.chunkSize {
 | 
			
		||||
      for y in 0..<Self.chunkSize {
 | 
			
		||||
        for z in 0..<Self.chunkSize {
 | 
			
		||||
          blocks[i].type = calculation(SIMD3(x, y, z))
 | 
			
		||||
          i += 1
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
@ -38,18 +38,26 @@ class Game: GameDelegate {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private func generateWorld() {
 | 
			
		||||
    var random: any RandomProvider
 | 
			
		||||
#if true
 | 
			
		||||
    let newSeed = UInt64(Arc4Random.instance.next()) | UInt64(Arc4Random.instance.next()) << 32
 | 
			
		||||
    printErr(newSeed)
 | 
			
		||||
    var random = Xoroshiro128PlusPlus(seed: newSeed)
 | 
			
		||||
    random = Xoroshiro128PlusPlus(seed: newSeed)
 | 
			
		||||
#else
 | 
			
		||||
    var random = PCG32Random(
 | 
			
		||||
      seed: UInt64(Arc4Random.instance.next()) | UInt64(Arc4Random.instance.next()) << 32,
 | 
			
		||||
      sequence: UInt64(Arc4Random.instance.next()) | UInt64(Arc4Random.instance.next()) << 32)
 | 
			
		||||
    random = PCG32Random(state: (
 | 
			
		||||
        UInt64(Arc4Random.instance.next()) | UInt64(Arc4Random.instance.next()) << 32,
 | 
			
		||||
        UInt64(Arc4Random.instance.next()) | UInt64(Arc4Random.instance.next()) << 32))
 | 
			
		||||
#endif
 | 
			
		||||
    self.chunk.fill(allBy: {
 | 
			
		||||
      if (random.next() & 0x1) == 0x1 {
 | 
			
		||||
        .solid(.init(rgb888: UInt32(random.next(in: 0..<0xFFFFFF+1))).linear)
 | 
			
		||||
    let noise = ImprovedPerlin<Float>(random: &random)
 | 
			
		||||
    self.chunk.fill(allBy: { position in
 | 
			
		||||
      let fpos = SIMD3<Float>(position)
 | 
			
		||||
      return if fpos.y / Float(Chunk.chunkSize)
 | 
			
		||||
          + noise.get(fpos * 0.07) * 0.7
 | 
			
		||||
          + noise.get(fpos * 0.321 + 100) * 0.3 < 0.6 {
 | 
			
		||||
        .solid(.init(
 | 
			
		||||
          r: Float16(noise.get(fpos * 0.1)),
 | 
			
		||||
          g: Float16(noise.get(fpos * 0.1 + 10)),
 | 
			
		||||
          b: Float16(noise.get(fpos * 0.1 + 100))).mix(.white, 0.4).linear)
 | 
			
		||||
      } else {
 | 
			
		||||
        .air
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
@ -3,8 +3,11 @@ public extension FloatingPoint {
 | 
			
		||||
  @inline(__always) var radians: Self { self * (Self.pi / 180) }
 | 
			
		||||
 | 
			
		||||
  @inline(__always) func lerp(_ a: Self, _ b: Self) -> Self { b * self + a * (1 - self) }
 | 
			
		||||
  @inline(__always) func mlerp(_ a: Self, _ b: Self) -> Self { a + (b - a) * self }
 | 
			
		||||
  @inline(__always) func mlerp(_ a: Self, _ b: Self) -> Self { a + self * (b - a) }
 | 
			
		||||
 | 
			
		||||
  @inline(__always) func clamp(_ a: Self, _ b: Self) -> Self { min(max(self, a), b) }
 | 
			
		||||
  @inline(__always) var saturated: Self { self.clamp(0, 1) }
 | 
			
		||||
 | 
			
		||||
  @inline(__always) func smoothStep() -> Self { self * self * (3 - 2 * self) }
 | 
			
		||||
  @inline(__always) func smootherStep() -> Self { self * self * self * (self * (self * 6 - 15) + 10) }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										56
									
								
								Sources/Voxelotl/Random/PerlinNoiseGenerator.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								Sources/Voxelotl/Random/PerlinNoiseGenerator.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,56 @@
 | 
			
		||||
import Foundation
 | 
			
		||||
 | 
			
		||||
public struct ImprovedPerlin<T: BinaryFloatingPoint & SIMDScalar> {
 | 
			
		||||
  private let p: [Int32]
 | 
			
		||||
 | 
			
		||||
  public init(random: inout any RandomProvider) {
 | 
			
		||||
    self.p = (0..<0x100).map { Int32($0) }.shuffled(using: &random)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public func get(_ point: SIMD3<T>) -> T {
 | 
			
		||||
    // Find unit cube containg point
 | 
			
		||||
    let idx = SIMD3(Int(floor(point.x)), Int(floor(point.y)), Int(floor(point.z))) & 0xFF
 | 
			
		||||
    // Find relative point in cube
 | 
			
		||||
    let inner = point - SIMD3(floor(point.x), floor(point.y), floor(point.z))
 | 
			
		||||
 | 
			
		||||
    // Compute fade curves for each axis
 | 
			
		||||
    let u = inner.x.smootherStep()
 | 
			
		||||
    let v = inner.y.smootherStep()
 | 
			
		||||
    let w = inner.z.smootherStep()
 | 
			
		||||
 | 
			
		||||
    // Compute hash of the coordinates of the 8 cube corners
 | 
			
		||||
    let a  = idx.y + perm(idx.x)
 | 
			
		||||
    let aa = idx.z + perm(a)
 | 
			
		||||
    let ab = idx.z + perm(a + 1)
 | 
			
		||||
    let b  = idx.y + perm(idx.x + 1)
 | 
			
		||||
    let ba = idx.z + perm(b)
 | 
			
		||||
    let bb = idx.z + perm(b + 1)
 | 
			
		||||
 | 
			
		||||
    // Add blended results
 | 
			
		||||
    return w.mlerp(v.mlerp(
 | 
			
		||||
        u.mlerp(
 | 
			
		||||
          grad(perm(aa), inner),
 | 
			
		||||
          grad(perm(ba), .init(inner.x - 1, inner.y, inner.z))),
 | 
			
		||||
        u.mlerp(
 | 
			
		||||
          grad(perm(ab), .init(inner.x, inner.y - 1, inner.z)),
 | 
			
		||||
          grad(perm(bb), .init(inner.x - 1, inner.y - 1, inner.z)))),
 | 
			
		||||
      v.mlerp(u.mlerp(
 | 
			
		||||
          grad(perm(aa + 1), .init(inner.x, inner.y, inner.z - 1)),
 | 
			
		||||
          grad(perm(ba + 1), .init(inner.x - 1, inner.y, inner.z - 1))),
 | 
			
		||||
        u.mlerp(
 | 
			
		||||
          grad(perm(ab + 1), .init(inner.x, inner.y - 1, inner.z - 1)),
 | 
			
		||||
          grad(perm(bb + 1), inner - .init(repeating: 1)))))
 | 
			
		||||
 | 
			
		||||
    @inline(__always) func perm(_ x: Int) -> Int { Int(self.p[x & 0xFF]) }
 | 
			
		||||
 | 
			
		||||
    func grad(_ hash: Int, _ point: SIMD3<T>) -> T {
 | 
			
		||||
      // Convert low 4 bits of hash code into 12 gradient directions
 | 
			
		||||
      let low4 = hash & 0xF
 | 
			
		||||
      var u = low4 < 8 ? point.x : point.y
 | 
			
		||||
      var v = low4 < 4 ? point.y : (low4 == 0b1100 || low4 == 0b1110 ? point.x : point.z)
 | 
			
		||||
      u = (low4 & 0x1) == 0 ? u : -u
 | 
			
		||||
      v = (low4 & 0x2) == 0 ? v : -v
 | 
			
		||||
      return u + v
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								Sources/Voxelotl/Random/RandomCollectionExtensions.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								Sources/Voxelotl/Random/RandomCollectionExtensions.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
public extension MutableCollection {
 | 
			
		||||
  mutating func shuffle<T: RandomProvider>(using provider: inout T) {
 | 
			
		||||
    guard self.count > 1 else {
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    for (first, remaining) in zip(self.indices, stride(from: 0x100, to: 1, by: -1)) {
 | 
			
		||||
      let i = self.index(first, offsetBy: provider.next(in: remaining))
 | 
			
		||||
      self.swapAt(first, i)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public extension Sequence {
 | 
			
		||||
  func shuffled<T: RandomProvider>(using provider: inout T) -> [Self.Element] {
 | 
			
		||||
    var copy = Array(self)
 | 
			
		||||
    copy.shuffle(using: &provider)
 | 
			
		||||
    return copy
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user