├── .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 |
--------------------------------------------------------------------------------