-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathperlin_noise.py
118 lines (101 loc) · 3.07 KB
/
perlin_noise.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import taichi as ti
import random
@ti.func
def fade(t: float) -> float:
return t * t * t * (t * (t * 6 - 15) + 10)
@ti.func
def grad(hash: int, x: float, y: float, z: float) -> float:
value = 0.0
hash = hash & 0xF
if hash == 0x0:
value = x + y
elif hash == 0x1:
value = -x + y
elif hash == 0x2:
value = x - y
elif hash == 0x3:
value = -x - y
elif hash == 0x4:
value = x + z
elif hash == 0x5:
value = -x + z
elif hash == 0x6:
value = x - z
elif hash == 0x7:
value = -x - z
elif hash == 0x8:
value = y + z
elif hash == 0x9:
value = -y + z
elif hash == 0xA:
value = y - z
elif hash == 0xB:
value = -y - z
elif hash == 0xC:
value = y + x
elif hash == 0xD:
value = -y + z
elif hash == 0xE:
value = y - x
elif hash == 0xF:
value = -y - z
return value
@ti.func
def lerp(x, y, t):
return x * (1 - t) + y * t
@ti.data_oriented
class PerlinNoise:
def __init__(self) -> None:
permutation = list(range(0, 256))
random.shuffle(permutation)
self.p = ti.field(dtype=int, shape=512)
for x in range(512):
self.p[x] = permutation[x % 256]
@ti.func
def noise(self, x: float, y: float, z: float) -> float:
xi = int(x) & 255
yi = int(y) & 255
zi = int(z) & 255
xf = x - int(x)
yf = y - int(y)
zf = z - int(z)
u = fade(xf)
v = fade(yf)
w = fade(zf)
aaa = self.p[self.p[self.p[xi] + yi] + zi]
aba = self.p[self.p[self.p[xi] + yi+1] + zi]
aab = self.p[self.p[self.p[xi] + yi] + zi+1]
abb = self.p[self.p[self.p[xi] + yi+1] + zi+1]
baa = self.p[self.p[self.p[xi+1] + yi] + zi]
bba = self.p[self.p[self.p[xi+1] + yi+1] + zi]
bab = self.p[self.p[self.p[xi+1] + yi] + zi+1]
bbb = self.p[self.p[self.p[xi+1] + yi+1] + zi+1]
x1 = lerp(grad(aaa, xf, yf, zf), grad(baa, xf-1, yf, zf), u)
x2 = lerp(grad(aba, xf, yf-1, zf), grad(bba, xf-1, yf-1, zf), u)
y1 = lerp(x1, x2, v)
x1 = lerp(grad(aab, xf, yf, zf-1), grad(bab, xf-1, yf, zf-1), u)
x2 = lerp(grad(abb, xf, yf-1, zf-1), grad(bbb, xf-1, yf-1, zf-1), u)
y2 = lerp(x1, x2, v)
return (lerp(y1, y2, w) + 1) / 2
@ti.kernel
def render(size: int):
for i, j in colors:
value = perlin.noise(i / size, j / size, 0.34)
colors[i, j] = (value, value, value)
if __name__ == '__main__':
ti.init(arch=ti.vulkan)
width, height = 1024, 1024
window = ti.ui.Window("Perlin noise", res=(width, height))
canvas = window.get_canvas()
gui = window.get_gui()
colors = ti.Vector.field(3, dtype=float, shape=(width, height))
perlin = PerlinNoise()
old_size = 64
render(old_size)
while window.running:
new_size = gui.slider_int("Size", old_size, 1, 128)
if new_size != old_size:
render(new_size)
old_size = new_size
canvas.set_image(colors)
window.show()