├── .gitignore ├── .swiftpm └── xcode │ └── xcshareddata │ └── xcschemes │ └── Noise.xcscheme ├── Assets ├── noise-color-layers.png ├── noise-colors.png ├── noise-random.png ├── noise-smooth.gif ├── noise-smooth.png └── noise.png ├── LICENSE ├── Package.swift ├── README.md └── Sources └── Noise ├── Helpers └── SizeReader.swift ├── Noise.swift └── Shaders ├── NoiseShader.metal ├── NoiseShader.swift └── Shared ├── noise.metal ├── noise_header.metal ├── random.metal └── random_header.metal /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | *.xcworkspace -------------------------------------------------------------------------------- /.swiftpm/xcode/xcshareddata/xcschemes/Noise.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 57 | 58 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Assets/noise-color-layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heestand-xyz/Noise/9fc3dd5b86995913f4cd58152f4d8d7da245ce7e/Assets/noise-color-layers.png -------------------------------------------------------------------------------- /Assets/noise-colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heestand-xyz/Noise/9fc3dd5b86995913f4cd58152f4d8d7da245ce7e/Assets/noise-colors.png -------------------------------------------------------------------------------- /Assets/noise-random.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heestand-xyz/Noise/9fc3dd5b86995913f4cd58152f4d8d7da245ce7e/Assets/noise-random.png -------------------------------------------------------------------------------- /Assets/noise-smooth.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heestand-xyz/Noise/9fc3dd5b86995913f4cd58152f4d8d7da245ce7e/Assets/noise-smooth.gif -------------------------------------------------------------------------------- /Assets/noise-smooth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heestand-xyz/Noise/9fc3dd5b86995913f4cd58152f4d8d7da245ce7e/Assets/noise-smooth.png -------------------------------------------------------------------------------- /Assets/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/heestand-xyz/Noise/9fc3dd5b86995913f4cd58152f4d8d7da245ce7e/Assets/noise.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Anton Heestand 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.9 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Noise", 7 | platforms: [ 8 | .iOS(.v17), 9 | .tvOS(.v17), 10 | .macOS(.v14), 11 | .visionOS(.v1) 12 | ], 13 | products: [ 14 | .library( 15 | name: "Noise", 16 | targets: ["Noise"]), 17 | ], 18 | targets: [ 19 | .target( 20 | name: "Noise", 21 | dependencies: [], 22 | resources: [ 23 | .process("Shaders/Shared"), 24 | .process("Shaders/NoiseShader.metal") 25 | ] 26 | ), 27 | ] 28 | ) 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Noise 2 | 3 | Generate random smooth cloudy noise. 4 | 5 | ## Swift Package 6 | 7 | ```swift 8 | .package(url: "https://github.com/heestand-xyz/Noise", from: "2.0.0") 9 | ``` 10 | 11 | ## Examples 12 | 13 | ```swift 14 | import SwiftUI 15 | import Noise 16 | ``` 17 | 18 | 19 | 20 | ```swift 21 | struct ContentView: View { 22 | var body: some View { 23 | Noise(style: .noisy) 24 | .monochrome() 25 | } 26 | } 27 | ``` 28 | 29 | 30 | 31 | ```swift 32 | struct ContentView: View { 33 | var body: some View { 34 | Noise(style: .smooth) 35 | .monochrome() 36 | .brightness(1.5) 37 | } 38 | } 39 | ``` 40 | 41 | 42 | 43 | ```swift 44 | struct ContentView: View { 45 | var body: some View { 46 | Noise(style: .random) 47 | .monochrome() 48 | } 49 | } 50 | ``` 51 | 52 | 53 | 54 | ```swift 55 | struct ContentView: View { 56 | var body: some View { 57 | Noise(style: .custom(octaves: 4)) 58 | .brightness(1.5) 59 | } 60 | } 61 | ``` 62 | 63 | 64 | 65 | ```swift 66 | struct ContentView: View { 67 | var body: some View { 68 | ZStack { 69 | Color.black 70 | Noise(style: .custom(octaves: 5)) 71 | .monochrome() 72 | .tint(.red) 73 | Noise(style: .smooth) 74 | .monochrome() 75 | .tint(.yellow) 76 | .seed(2) 77 | .blendMode(.screen) 78 | } 79 | } 80 | } 81 | ``` 82 | 83 | 84 | 85 | ```swift 86 | struct ContentView: View { 87 | var body: some View { 88 | Noise(style: .smooth, speed: 1.0) 89 | .monochrome() 90 | } 91 | } 92 | ``` 93 | 94 | Graphics Powered by SwiftUI Metal Shaders 95 | 96 | Original Noise by [Eliot Eshelman](https://github.com/eshelman) 97 | -------------------------------------------------------------------------------- /Sources/Noise/Helpers/SizeReader.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct SizeReader: View { 4 | 5 | @ViewBuilder 6 | let content: (CGSize) -> Content 7 | 8 | @State private var size: CGSize = CGSize(width: 1.0, height: 1.0) 9 | 10 | var body: some View { 11 | content(size) 12 | .background { 13 | GeometryReader { proxy in 14 | Color.clear 15 | .onAppear { 16 | size = proxy.size 17 | } 18 | .onChange(of: proxy.size) { _, newSize in 19 | size = newSize 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Noise/Noise.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import Combine 3 | 4 | public struct Noise: View { 5 | 6 | @State private var id: UUID = UUID() 7 | 8 | @Environment(\.colorScheme) var colorScheme 9 | 10 | private let color: Color? 11 | private let brightness: Double? 12 | private let colored: Bool 13 | private let scale: CGFloat 14 | private let seed: Int 15 | private let speed: Double 16 | 17 | public enum Style: Equatable { 18 | case noisy 19 | case smooth 20 | case random 21 | /// Octaves between 1 and 10. The higher number the more noise. 22 | case custom(octaves: Int) 23 | var octaves: Int { 24 | switch self { 25 | case .noisy: 26 | 10 27 | case .smooth: 28 | 1 29 | case .random: 30 | 1 31 | case .custom(let octaves): 32 | min(10, max(1, octaves)) 33 | } 34 | } 35 | } 36 | let style: Style 37 | 38 | @available(*, deprecated, renamed: "init(style:speed:)") 39 | public init(smoothness: Double? = 0.0, 40 | speed: Double = 0.0) { 41 | color = nil 42 | brightness = nil 43 | colored = false 44 | seed = 0 45 | scale = 1.0 46 | style = if let smoothness { 47 | .custom(octaves: 1 + Int((1.0 - min(1.0, max(0.0, smoothness))) * 9)) 48 | } else { 49 | .random 50 | } 51 | self.speed = speed 52 | } 53 | 54 | public init(style: Style, 55 | speed: Double = 0.0) { 56 | color = nil 57 | brightness = nil 58 | colored = true 59 | seed = 0 60 | scale = 1.0 61 | self.style = style 62 | self.speed = speed 63 | } 64 | 65 | private init(color: Color?, 66 | brightness: Double?, 67 | colored: Bool, 68 | scale: CGFloat, 69 | seed: Int, 70 | style: Style, 71 | speed: Double) { 72 | self.color = color 73 | self.brightness = brightness 74 | self.colored = colored 75 | self.scale = scale 76 | self.seed = seed 77 | self.style = style 78 | self.speed = speed 79 | } 80 | 81 | @State private var time: TimeInterval = 0.0 82 | @State private var lastDate: Date = .now 83 | 84 | public var body: some View { 85 | if speed == 0.0, time == 0.0 { 86 | NoiseShader( 87 | octaves: style.octaves, 88 | offset: .zero, 89 | zOffset: 0.0, 90 | scale: scale, 91 | isColored: colored, 92 | isRandom: style == .random, 93 | tint: color ?? .white, 94 | brightness: brightness ?? 1.0, 95 | seed: seed 96 | ) 97 | } else { 98 | SizeReader { size in 99 | TimelineView(.animation) { context in 100 | let zOffset: CGFloat = time * size.height 101 | let randomSeed = Int(time) 102 | NoiseShader( 103 | octaves: style.octaves, 104 | offset: .zero, 105 | zOffset: zOffset, 106 | scale: scale, 107 | isColored: colored, 108 | isRandom: style == .random, 109 | tint: color ?? .white, 110 | brightness: brightness ?? 1.0, 111 | seed: style == .random ? randomSeed : seed 112 | ) 113 | .onChange(of: context.date) { _, newDate in 114 | time += lastDate.distance(to: newDate) * speed 115 | lastDate = newDate 116 | } 117 | } 118 | } 119 | } 120 | } 121 | } 122 | 123 | extension Noise { 124 | 125 | public func scale(_ scale: CGFloat) -> Noise { 126 | Noise( 127 | color: color, 128 | brightness: brightness, 129 | colored: colored, 130 | scale: scale, 131 | seed: seed, 132 | style: style, 133 | speed: speed 134 | ) 135 | } 136 | 137 | public func seed(_ seed: Int) -> Noise { 138 | Noise( 139 | color: color, 140 | brightness: brightness, 141 | colored: colored, 142 | scale: scale, 143 | seed: seed, 144 | style: style, 145 | speed: speed 146 | ) 147 | } 148 | 149 | @available(*, deprecated, message: "The noise is now colored by default.") 150 | public func foregroundColors() -> Noise { 151 | self 152 | } 153 | 154 | @available(*, deprecated, renamed: "tint(_:)") 155 | public func foregroundColor(_ color: Color) -> Noise { 156 | tint(color) 157 | } 158 | 159 | public func monochrome() -> Noise { 160 | Noise( 161 | color: color, 162 | brightness: brightness, 163 | colored: false, 164 | scale: scale, 165 | seed: seed, 166 | style: style, 167 | speed: speed 168 | ) 169 | } 170 | 171 | public func tint(_ color: Color) -> Noise { 172 | Noise( 173 | color: color, 174 | brightness: brightness, 175 | colored: colored, 176 | scale: scale, 177 | seed: seed, 178 | style: style, 179 | speed: speed 180 | ) 181 | } 182 | 183 | public func brightness(_ amount: Double) -> Noise { 184 | Noise( 185 | color: color, 186 | brightness: amount, 187 | colored: colored, 188 | scale: scale, 189 | seed: seed, 190 | style: style, 191 | speed: speed 192 | ) 193 | } 194 | } 195 | 196 | #Preview { 197 | Noise(style: .smooth) 198 | } 199 | -------------------------------------------------------------------------------- /Sources/Noise/Shaders/NoiseShader.metal: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Anton Heestand on 2017-11-24. 3 | // Copyright © 2017 Anton Heestand. All rights reserved. 4 | // 5 | 6 | #include 7 | using namespace metal; 8 | 9 | #import "Shared/noise_header.metal" 10 | #import "Shared/random_header.metal" 11 | 12 | [[ stitchable ]] half4 noise(float2 position, 13 | half4 color, 14 | float2 size, 15 | float octaves, 16 | float2 offset, 17 | float zOffset, 18 | float scale, 19 | float isColored, 20 | float isRandom, 21 | half4 tint, 22 | float brightness, 23 | float seed) { 24 | 25 | int max_res = 16384 - 1; 26 | 27 | float width = size.x; 28 | float height = size.y; 29 | float aspectRatio = width / height; 30 | 31 | float u = position.x / width; 32 | float v = position.y / height; 33 | 34 | float ux = ((u - 0.5) * aspectRatio - (offset.x / height)) / scale; 35 | float vy = ((v - 0.5) - (offset.y / height)) / scale; 36 | float wz = zOffset / height; 37 | 38 | float noise; 39 | if (isRandom == 1.0) { 40 | Loki loki_rnd = Loki(seed, u * max_res, v * max_res); 41 | noise = loki_rnd.rand(); 42 | } else { 43 | noise = octave_noise_3d(octaves, 0.5, 1.0, ux, vy, wz + seed * 100); 44 | noise = noise * 0.5 + 0.5; 45 | } 46 | 47 | float noiseGreen; 48 | float noiseBlue; 49 | if (isColored == 1.0) { 50 | if (isRandom == 1.0) { 51 | Loki loki_rnd_g = Loki(seed + 100, u * max_res, v * max_res); 52 | noiseGreen = loki_rnd_g.rand(); 53 | Loki loki_rnd_b = Loki(seed + 200, u * max_res, v * max_res); 54 | noiseBlue = loki_rnd_b.rand(); 55 | } else { 56 | noiseGreen = octave_noise_3d(octaves, 0.5, 1.0, ux, vy, wz + 10 + seed); 57 | noiseGreen = noiseGreen * 0.5 + 0.5; 58 | noiseBlue = octave_noise_3d(octaves, 0.5, 1.0, ux, vy, wz + 20 + seed); 59 | noiseBlue = noiseBlue * 0.5 + 0.5; 60 | } 61 | } 62 | 63 | float red = noise; 64 | float green = isColored ? noiseGreen : noise; 65 | float blue = isColored ? noiseBlue : noise; 66 | float4 noiseColor = float4(red * tint.r * brightness, 67 | green * tint.g * brightness, 68 | blue * tint.b * brightness, 69 | 1.0); 70 | 71 | return half4(noiseColor); 72 | } 73 | -------------------------------------------------------------------------------- /Sources/Noise/Shaders/NoiseShader.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct NoiseShader: View { 4 | 5 | let octaves: Int 6 | let offset: CGPoint 7 | let zOffset: CGFloat 8 | let scale: CGFloat 9 | let isColored: Bool 10 | let isRandom: Bool 11 | let tint: Color 12 | let brightness: CGFloat 13 | let seed: Int 14 | 15 | private var shaderFunction: ShaderFunction { 16 | ShaderFunction(library: .bundle(.module), 17 | name: "noise") 18 | } 19 | 20 | private func shader(size: CGSize) -> Shader { 21 | Shader(function: shaderFunction, arguments: [ 22 | .float2(size), 23 | .float(CGFloat(octaves)), 24 | .float2(offset), 25 | .float(zOffset), 26 | .float(scale), 27 | .float(isColored ? 1.0 : 0.0), 28 | .float(isRandom ? 1.0 : 0.0), 29 | .color(tint), 30 | .float(brightness), 31 | .float(CGFloat(seed)), 32 | ]) 33 | } 34 | 35 | var body: some View { 36 | SizeReader { size in 37 | Rectangle() 38 | .colorEffect(shader(size: size)) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Sources/Noise/Shaders/Shared/noise.metal: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007-2012 Eliot Eshelman 2 | * 3 | * This program is free software: you can redistribute it and/or modify 4 | * it under the terms of the GNU General Public License as published by 5 | * the Free Software Foundation, either version 3 of the License, or 6 | * (at your option) any later version. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License 14 | * along with this program. If not, see . 15 | * 16 | */ 17 | 18 | 19 | #include 20 | using namespace metal; 21 | 22 | 23 | #import "noise_header.metal" 24 | 25 | 26 | // 2D Multi-octave Simplex noise. 27 | // 28 | // For each octave, a higher frequency/lower amplitude function will be added to the original. 29 | // The higher the persistence [0-1], the more of each succeeding octave will be added. 30 | float octave_noise_2d( const float octaves, const float persistence, const float scale, const float x, const float y ) { 31 | float total = 0; 32 | float frequency = scale; 33 | float amplitude = 1; 34 | 35 | // We have to keep track of the largest possible amplitude, 36 | // because each octave adds more, and we need a value in [-1, 1]. 37 | float maxAmplitude = 0; 38 | 39 | for( int i=0; i < octaves; i++ ) { 40 | total += raw_noise_2d( x * frequency, y * frequency ) * amplitude; 41 | 42 | frequency *= 2; 43 | maxAmplitude += amplitude; 44 | amplitude *= persistence; 45 | } 46 | 47 | return total / maxAmplitude; 48 | } 49 | 50 | 51 | // 3D Multi-octave Simplex noise. 52 | // 53 | // For each octave, a higher frequency/lower amplitude function will be added to the original. 54 | // The higher the persistence [0-1], the more of each succeeding octave will be added. 55 | float octave_noise_3d( const float octaves, const float persistence, const float scale, const float x, const float y, const float z ) { 56 | float total = 0; 57 | float frequency = scale; 58 | float amplitude = 1; 59 | 60 | // We have to keep track of the largest possible amplitude, 61 | // because each octave adds more, and we need a value in [-1, 1]. 62 | float maxAmplitude = 0; 63 | 64 | for( int i=0; i < octaves; i++ ) { 65 | total += raw_noise_3d( x * frequency, y * frequency, z * frequency ) * amplitude; 66 | 67 | frequency *= 2; 68 | maxAmplitude += amplitude; 69 | amplitude *= persistence; 70 | } 71 | 72 | return total / maxAmplitude; 73 | } 74 | 75 | 76 | // 4D Multi-octave Simplex noise. 77 | // 78 | // For each octave, a higher frequency/lower amplitude function will be added to the original. 79 | // The higher the persistence [0-1], the more of each succeeding octave will be added. 80 | float octave_noise_4d( const float octaves, const float persistence, const float scale, const float x, const float y, const float z, const float w ) { 81 | float total = 0; 82 | float frequency = scale; 83 | float amplitude = 1; 84 | 85 | // We have to keep track of the largest possible amplitude, 86 | // because each octave adds more, and we need a value in [-1, 1]. 87 | float maxAmplitude = 0; 88 | 89 | for( int i=0; i < octaves; i++ ) { 90 | total += raw_noise_4d( x * frequency, y * frequency, z * frequency, w * frequency ) * amplitude; 91 | 92 | frequency *= 2; 93 | maxAmplitude += amplitude; 94 | amplitude *= persistence; 95 | } 96 | 97 | return total / maxAmplitude; 98 | } 99 | 100 | 101 | 102 | // 2D Scaled Multi-octave Simplex noise. 103 | // 104 | // Returned value will be between loBound and hiBound. 105 | float scaled_octave_noise_2d( const float octaves, const float persistence, const float scale, const float loBound, const float hiBound, const float x, const float y ) { 106 | return octave_noise_2d(octaves, persistence, scale, x, y) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2; 107 | } 108 | 109 | 110 | // 3D Scaled Multi-octave Simplex noise. 111 | // 112 | // Returned value will be between loBound and hiBound. 113 | float scaled_octave_noise_3d( const float octaves, const float persistence, const float scale, const float loBound, const float hiBound, const float x, const float y, const float z ) { 114 | return octave_noise_3d(octaves, persistence, scale, x, y, z) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2; 115 | } 116 | 117 | // 4D Scaled Multi-octave Simplex noise. 118 | // 119 | // Returned value will be between loBound and hiBound. 120 | float scaled_octave_noise_4d( const float octaves, const float persistence, const float scale, const float loBound, const float hiBound, const float x, const float y, const float z, const float w ) { 121 | return octave_noise_4d(octaves, persistence, scale, x, y, z, w) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2; 122 | } 123 | 124 | 125 | 126 | // 2D Scaled Simplex raw noise. 127 | // 128 | // Returned value will be between loBound and hiBound. 129 | float scaled_raw_noise_2d( const float loBound, const float hiBound, const float x, const float y ) { 130 | return raw_noise_2d(x, y) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2; 131 | } 132 | 133 | 134 | // 3D Scaled Simplex raw noise. 135 | // 136 | // Returned value will be between loBound and hiBound. 137 | float scaled_raw_noise_3d( const float loBound, const float hiBound, const float x, const float y, const float z ) { 138 | return raw_noise_3d(x, y, z) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2; 139 | } 140 | 141 | // 4D Scaled Simplex raw noise. 142 | // 143 | // Returned value will be between loBound and hiBound. 144 | float scaled_raw_noise_4d( const float loBound, const float hiBound, const float x, const float y, const float z, const float w ) { 145 | return raw_noise_4d(x, y, z, w) * (hiBound - loBound) / 2 + (hiBound + loBound) / 2; 146 | } 147 | 148 | constant int perm[512] = { 149 | 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142, 150 | 8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117, 151 | 35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71, 152 | 134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41, 153 | 55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208, 89, 154 | 18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226, 155 | 250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182, 156 | 189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43, 157 | 172,9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,246,97, 158 | 228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239, 159 | 107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254, 160 | 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, 161 | 162 | 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142, 163 | 8,99,37,240,21,10,23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117, 164 | 35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71, 165 | 134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41, 166 | 55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208, 89, 167 | 18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226, 168 | 250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182, 169 | 189,28,42,223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43, 170 | 172,9,129,22,39,253,19,98,108,110,79,113,224,232,178,185,112,104,218,246,97, 171 | 228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239, 172 | 107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254, 173 | 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 174 | }; 175 | 176 | constant int grad3[12][3] = { 177 | {1,1,0}, {-1,1,0}, {1,-1,0}, {-1,-1,0}, 178 | {1,0,1}, {-1,0,1}, {1,0,-1}, {-1,0,-1}, 179 | {0,1,1}, {0,-1,1}, {0,1,-1}, {0,-1,-1} 180 | }; 181 | constant int grad4[32][4] = { 182 | {0,1,1,1}, {0,1,1,-1}, {0,1,-1,1}, {0,1,-1,-1}, 183 | {0,-1,1,1}, {0,-1,1,-1}, {0,-1,-1,1}, {0,-1,-1,-1}, 184 | {1,0,1,1}, {1,0,1,-1}, {1,0,-1,1}, {1,0,-1,-1}, 185 | {-1,0,1,1}, {-1,0,1,-1}, {-1,0,-1,1}, {-1,0,-1,-1}, 186 | {1,1,0,1}, {1,1,0,-1}, {1,-1,0,1}, {1,-1,0,-1}, 187 | {-1,1,0,1}, {-1,1,0,-1}, {-1,-1,0,1}, {-1,-1,0,-1}, 188 | {1,1,1,0}, {1,1,-1,0}, {1,-1,1,0}, {1,-1,-1,0}, 189 | {-1,1,1,0}, {-1,1,-1,0}, {-1,-1,1,0}, {-1,-1,-1,0} 190 | }; 191 | 192 | constant int simplex[64][4] = { 193 | {0,1,2,3},{0,1,3,2},{0,0,0,0},{0,2,3,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,2,3,0}, 194 | {0,2,1,3},{0,0,0,0},{0,3,1,2},{0,3,2,1},{0,0,0,0},{0,0,0,0},{0,0,0,0},{1,3,2,0}, 195 | {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, 196 | {1,2,0,3},{0,0,0,0},{1,3,0,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,3,0,1},{2,3,1,0}, 197 | {1,0,2,3},{1,0,3,2},{0,0,0,0},{0,0,0,0},{0,0,0,0},{2,0,3,1},{0,0,0,0},{2,1,3,0}, 198 | {0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}, 199 | {2,0,1,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,0,1,2},{3,0,2,1},{0,0,0,0},{3,1,2,0}, 200 | {2,1,0,3},{0,0,0,0},{0,0,0,0},{0,0,0,0},{3,1,0,2},{0,0,0,0},{3,2,0,1},{3,2,1,0} 201 | }; 202 | 203 | // 2D raw Simplex noise 204 | float raw_noise_2d( const float x, const float y ) { 205 | // Noise contributions from the three corners 206 | float n0, n1, n2; 207 | 208 | // Skew the input space to determine which simplex cell we're in 209 | float F2 = 0.5 * (sqrt(3.0) - 1.0); 210 | // Hairy factor for 2D 211 | float s = (x + y) * F2; 212 | int i = floor( x + s ); 213 | int j = floor( y + s ); 214 | 215 | float G2 = (3.0 - sqrt(3.0)) / 6.0; 216 | float t = (i + j) * G2; 217 | // Unskew the cell origin back to (x,y) space 218 | float X0 = i-t; 219 | float Y0 = j-t; 220 | // The x,y distances from the cell origin 221 | float x0 = x-X0; 222 | float y0 = y-Y0; 223 | 224 | // For the 2D case, the simplex shape is an equilateral triangle. 225 | // Determine which simplex we are in. 226 | int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords 227 | if(x0>y0) {i1=1; j1=0;} // lower triangle, XY order: (0,0)->(1,0)->(1,1) 228 | else {i1=0; j1=1;} // upper triangle, YX order: (0,0)->(0,1)->(1,1) 229 | 230 | // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and 231 | // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where 232 | // c = (3-sqrt(3))/6 233 | float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords 234 | float y1 = y0 - j1 + G2; 235 | float x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords 236 | float y2 = y0 - 1.0 + 2.0 * G2; 237 | 238 | // Work out the hashed gradient indices of the three simplex corners 239 | int ii = i & 255; 240 | int jj = j & 255; 241 | int gi0 = perm[ii+perm[jj]] % 12; 242 | int gi1 = perm[ii+i1+perm[jj+j1]] % 12; 243 | int gi2 = perm[ii+1+perm[jj+1]] % 12; 244 | 245 | // Calculate the contribution from the three corners 246 | float t0 = 0.5 - x0*x0-y0*y0; 247 | if(t0<0) n0 = 0.0; 248 | else { 249 | t0 *= t0; 250 | n0 = t0 * t0 * dot(grad3[gi0], x0, y0); // (x,y) of grad3 used for 2D gradient 251 | } 252 | 253 | float t1 = 0.5 - x1*x1-y1*y1; 254 | if(t1<0) n1 = 0.0; 255 | else { 256 | t1 *= t1; 257 | n1 = t1 * t1 * dot(grad3[gi1], x1, y1); 258 | } 259 | 260 | float t2 = 0.5 - x2*x2-y2*y2; 261 | if(t2<0) n2 = 0.0; 262 | else { 263 | t2 *= t2; 264 | n2 = t2 * t2 * dot(grad3[gi2], x2, y2); 265 | } 266 | 267 | // Add contributions from each corner to get the final noise value. 268 | // The result is scaled to return values in the interval [-1,1]. 269 | return 70.0 * (n0 + n1 + n2); 270 | } 271 | 272 | 273 | // 3D raw Simplex noise 274 | float raw_noise_3d( const float x, const float y, const float z ) { 275 | float n0, n1, n2, n3; // Noise contributions from the four corners 276 | 277 | // Skew the input space to determine which simplex cell we're in 278 | float F3 = 1.0/3.0; 279 | float s = (x+y+z)*F3; // Very nice and simple skew factor for 3D 280 | int i = floor(x+s); 281 | int j = floor(y+s); 282 | int k = floor(z+s); 283 | 284 | float G3 = 1.0/6.0; // Very nice and simple unskew factor, too 285 | float t = (i+j+k)*G3; 286 | float X0 = i-t; // Unskew the cell origin back to (x,y,z) space 287 | float Y0 = j-t; 288 | float Z0 = k-t; 289 | float x0 = x-X0; // The x,y,z distances from the cell origin 290 | float y0 = y-Y0; 291 | float z0 = z-Z0; 292 | 293 | // For the 3D case, the simplex shape is a slightly irregular tetrahedron. 294 | // Determine which simplex we are in. 295 | int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords 296 | int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords 297 | 298 | if(x0>=y0) { 299 | if(y0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } // X Y Z order 300 | else if(x0>=z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } // X Z Y order 301 | else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } // Z X Y order 302 | } 303 | else { // x0 y0) ? 32 : 0; 400 | int c2 = (x0 > z0) ? 16 : 0; 401 | int c3 = (y0 > z0) ? 8 : 0; 402 | int c4 = (x0 > w0) ? 4 : 0; 403 | int c5 = (y0 > w0) ? 2 : 0; 404 | int c6 = (z0 > w0) ? 1 : 0; 405 | int c = c1 + c2 + c3 + c4 + c5 + c6; 406 | 407 | int i1, j1, k1, l1; // The integer offsets for the second simplex corner 408 | int i2, j2, k2, l2; // The integer offsets for the third simplex corner 409 | int i3, j3, k3, l3; // The integer offsets for the fourth simplex corner 410 | 411 | // simplex[c] is a 4-vector with the numbers 0, 1, 2 and 3 in some order. 412 | // Many values of c will never occur, since e.g. x>y>z>w makes x=3 ? 1 : 0; 417 | j1 = simplex[c][1]>=3 ? 1 : 0; 418 | k1 = simplex[c][2]>=3 ? 1 : 0; 419 | l1 = simplex[c][3]>=3 ? 1 : 0; 420 | // The number 2 in the "simplex" array is at the second largest coordinate. 421 | i2 = simplex[c][0]>=2 ? 1 : 0; 422 | j2 = simplex[c][1]>=2 ? 1 : 0; 423 | k2 = simplex[c][2]>=2 ? 1 : 0; 424 | l2 = simplex[c][3]>=2 ? 1 : 0; 425 | // The number 1 in the "simplex" array is at the second smallest coordinate. 426 | i3 = simplex[c][0]>=1 ? 1 : 0; 427 | j3 = simplex[c][1]>=1 ? 1 : 0; 428 | k3 = simplex[c][2]>=1 ? 1 : 0; 429 | l3 = simplex[c][3]>=1 ? 1 : 0; 430 | // The fifth corner has all coordinate offsets = 1, so no need to look that up. 431 | 432 | float x1 = x0 - i1 + G4; // Offsets for second corner in (x,y,z,w) coords 433 | float y1 = y0 - j1 + G4; 434 | float z1 = z0 - k1 + G4; 435 | float w1 = w0 - l1 + G4; 436 | float x2 = x0 - i2 + 2.0*G4; // Offsets for third corner in (x,y,z,w) coords 437 | float y2 = y0 - j2 + 2.0*G4; 438 | float z2 = z0 - k2 + 2.0*G4; 439 | float w2 = w0 - l2 + 2.0*G4; 440 | float x3 = x0 - i3 + 3.0*G4; // Offsets for fourth corner in (x,y,z,w) coords 441 | float y3 = y0 - j3 + 3.0*G4; 442 | float z3 = z0 - k3 + 3.0*G4; 443 | float w3 = w0 - l3 + 3.0*G4; 444 | float x4 = x0 - 1.0 + 4.0*G4; // Offsets for last corner in (x,y,z,w) coords 445 | float y4 = y0 - 1.0 + 4.0*G4; 446 | float z4 = z0 - 1.0 + 4.0*G4; 447 | float w4 = w0 - 1.0 + 4.0*G4; 448 | 449 | // Work out the hashed gradient indices of the five simplex corners 450 | int ii = i & 255; 451 | int jj = j & 255; 452 | int kk = k & 255; 453 | int ll = l & 255; 454 | int gi0 = perm[ii+perm[jj+perm[kk+perm[ll]]]] % 32; 455 | int gi1 = perm[ii+i1+perm[jj+j1+perm[kk+k1+perm[ll+l1]]]] % 32; 456 | int gi2 = perm[ii+i2+perm[jj+j2+perm[kk+k2+perm[ll+l2]]]] % 32; 457 | int gi3 = perm[ii+i3+perm[jj+j3+perm[kk+k3+perm[ll+l3]]]] % 32; 458 | int gi4 = perm[ii+1+perm[jj+1+perm[kk+1+perm[ll+1]]]] % 32; 459 | 460 | // Calculate the contribution from the five corners 461 | float t0 = 0.6 - x0*x0 - y0*y0 - z0*z0 - w0*w0; 462 | if(t0<0) n0 = 0.0; 463 | else { 464 | t0 *= t0; 465 | n0 = t0 * t0 * dot(grad4[gi0], x0, y0, z0, w0); 466 | } 467 | 468 | float t1 = 0.6 - x1*x1 - y1*y1 - z1*z1 - w1*w1; 469 | if(t1<0) n1 = 0.0; 470 | else { 471 | t1 *= t1; 472 | n1 = t1 * t1 * dot(grad4[gi1], x1, y1, z1, w1); 473 | } 474 | 475 | float t2 = 0.6 - x2*x2 - y2*y2 - z2*z2 - w2*w2; 476 | if(t2<0) n2 = 0.0; 477 | else { 478 | t2 *= t2; 479 | n2 = t2 * t2 * dot(grad4[gi2], x2, y2, z2, w2); 480 | } 481 | 482 | float t3 = 0.6 - x3*x3 - y3*y3 - z3*z3 - w3*w3; 483 | if(t3<0) n3 = 0.0; 484 | else { 485 | t3 *= t3; 486 | n3 = t3 * t3 * dot(grad4[gi3], x3, y3, z3, w3); 487 | } 488 | 489 | float t4 = 0.6 - x4*x4 - y4*y4 - z4*z4 - w4*w4; 490 | if(t4<0) n4 = 0.0; 491 | else { 492 | t4 *= t4; 493 | n4 = t4 * t4 * dot(grad4[gi4], x4, y4, z4, w4); 494 | } 495 | 496 | // Sum up and scale the result to cover the range [-1,1] 497 | return 27.0 * (n0 + n1 + n2 + n3 + n4); 498 | } 499 | 500 | float dot( constant int g[2], const float x, const float y ) { return g[0]*x + g[1]*y; } 501 | float dot( constant int g[3], const float x, const float y, const float z ) { return g[0]*x + g[1]*y + g[2]*z; } 502 | float dot( constant int g[4], const float x, const float y, const float z, const float w ) { return g[0]*x + g[1]*y + g[2]*z + g[3]*w; } 503 | -------------------------------------------------------------------------------- /Sources/Noise/Shaders/Shared/noise_header.metal: -------------------------------------------------------------------------------- 1 | // 2 | // noise_header.metal 3 | // 4 | 5 | #include 6 | using namespace metal; 7 | 8 | #ifndef NOISE 9 | #define NOISE 10 | 11 | 12 | // Multi-octave Simplex noise 13 | // For each octave, a higher frequency/lower amplitude function will be added to the original. 14 | // The higher the persistence [0-1], the more of each succeeding octave will be added. 15 | float octave_noise_2d(const float octaves, 16 | const float persistence, 17 | const float scale, 18 | const float x, 19 | const float y); 20 | float octave_noise_3d(const float octaves, 21 | const float persistence, 22 | const float scale, 23 | const float x, 24 | const float y, 25 | const float z); 26 | float octave_noise_4d(const float octaves, 27 | const float persistence, 28 | const float scale, 29 | const float x, 30 | const float y, 31 | const float z, 32 | const float w); 33 | 34 | 35 | // Scaled Multi-octave Simplex noise 36 | // The result will be between the two parameters passed. 37 | float scaled_octave_noise_2d( const float octaves, 38 | const float persistence, 39 | const float scale, 40 | const float loBound, 41 | const float hiBound, 42 | const float x, 43 | const float y); 44 | float scaled_octave_noise_3d( const float octaves, 45 | const float persistence, 46 | const float scale, 47 | const float loBound, 48 | const float hiBound, 49 | const float x, 50 | const float y, 51 | const float z); 52 | float scaled_octave_noise_4d( const float octaves, 53 | const float persistence, 54 | const float scale, 55 | const float loBound, 56 | const float hiBound, 57 | const float x, 58 | const float y, 59 | const float z, 60 | const float w); 61 | 62 | // Scaled Raw Simplex noise 63 | // The result will be between the two parameters passed. 64 | float scaled_raw_noise_2d( const float loBound, 65 | const float hiBound, 66 | const float x, 67 | const float y); 68 | float scaled_raw_noise_3d( const float loBound, 69 | const float hiBound, 70 | const float x, 71 | const float y, 72 | const float z); 73 | float scaled_raw_noise_4d( const float loBound, 74 | const float hiBound, 75 | const float x, 76 | const float y, 77 | const float z, 78 | const float w); 79 | 80 | 81 | // Raw Simplex noise - a single noise value. 82 | float raw_noise_2d(const float x, const float y); 83 | float raw_noise_3d(const float x, const float y, const float z); 84 | float raw_noise_4d(const float x, const float y, const float, const float w); 85 | 86 | float dot(constant int g[2], const float x, const float y); 87 | float dot(constant int g[3], const float x, const float y, const float z); 88 | float dot(constant int g[4], const float x, const float y, const float z, const float w); 89 | 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /Sources/Noise/Shaders/Shared/random.metal: -------------------------------------------------------------------------------- 1 | #include 2 | #include "random_header.metal" 3 | 4 | unsigned Loki::TausStep(const unsigned z, const int s1, const int s2, const int s3, const unsigned M) 5 | { 6 | unsigned b=(((z << s1) ^ z) >> s2); 7 | return (((z & M) << s3) ^ b); 8 | } 9 | 10 | thread Loki::Loki(const unsigned seed1, const unsigned seed2, const unsigned seed3) { 11 | unsigned seed = seed1 * 1099087573UL; 12 | unsigned seedb = seed2 * 1099087573UL; 13 | unsigned seedc = seed3 * 1099087573UL; 14 | 15 | // Round 1: Randomise seed 16 | unsigned z1 = TausStep(seed,13,19,12,429496729UL); 17 | unsigned z2 = TausStep(seed,2,25,4,4294967288UL); 18 | unsigned z3 = TausStep(seed,3,11,17,429496280UL); 19 | unsigned z4 = (1664525*seed + 1013904223UL); 20 | 21 | // Round 2: Randomise seed again using second seed 22 | unsigned r1 = (z1^z2^z3^z4^seedb); 23 | 24 | z1 = TausStep(r1,13,19,12,429496729UL); 25 | z2 = TausStep(r1,2,25,4,4294967288UL); 26 | z3 = TausStep(r1,3,11,17,429496280UL); 27 | z4 = (1664525*r1 + 1013904223UL); 28 | 29 | // Round 3: Randomise seed again using third seed 30 | r1 = (z1^z2^z3^z4^seedc); 31 | 32 | z1 = TausStep(r1,13,19,12,429496729UL); 33 | z2 = TausStep(r1,2,25,4,4294967288UL); 34 | z3 = TausStep(r1,3,11,17,429496280UL); 35 | z4 = (1664525*r1 + 1013904223UL); 36 | 37 | this->seed = (z1^z2^z3^z4) * 2.3283064365387e-10; 38 | } 39 | 40 | thread float Loki::rand() { 41 | unsigned hashed_seed = this->seed * 1099087573UL; 42 | 43 | unsigned z1 = TausStep(hashed_seed,13,19,12,429496729UL); 44 | unsigned z2 = TausStep(hashed_seed,2,25,4,4294967288UL); 45 | unsigned z3 = TausStep(hashed_seed,3,11,17,429496280UL); 46 | unsigned z4 = (1664525*hashed_seed + 1013904223UL); 47 | 48 | thread float old_seed = this->seed; 49 | 50 | this->seed = (z1^z2^z3^z4) * 2.3283064365387e-10; 51 | 52 | return old_seed; 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Noise/Shaders/Shared/random_header.metal: -------------------------------------------------------------------------------- 1 | /* 2 | * Loki Random Number Generator 3 | * Copyright (c) 2017 Youssef Victor All rights reserved. 4 | * 5 | * Function Result 6 | * ------------------------------------------------------------------ 7 | * 8 | * TausStep Combined Tausworthe Generator or 9 | * Linear Feedback Shift Register (LFSR) 10 | * random number generator. This is a 11 | * helper method for rng, which uses 12 | * a hybrid approach combining LFSR with 13 | * a Linear Congruential Generator (LCG) 14 | * in order to produce random numbers with 15 | * periods of well over 2^121 16 | * 17 | * rand A pseudo-random number based on the 18 | * method outlined in "Efficient 19 | * pseudo-random number generation 20 | * for monte-carlo simulations using 21 | * graphic processors" by Siddhant 22 | * Mohanty et al 2012. 23 | * 24 | */ 25 | 26 | #include 27 | using namespace metal; 28 | 29 | #ifndef LOKI 30 | #define LOKI 31 | 32 | 33 | class Loki { 34 | private: 35 | thread float seed; 36 | unsigned TausStep(const unsigned z, const int s1, const int s2, const int s3, const unsigned M); 37 | 38 | public: 39 | thread Loki(const unsigned seed1, const unsigned seed2 = 1, const unsigned seed3 = 1); 40 | 41 | thread float rand(); 42 | }; 43 | 44 | #endif 45 | --------------------------------------------------------------------------------