Mandelbrot set: Difference between revisions
Content added Content deleted
m (→Normal Map Effect, Mercator Projection and Deep Zoom Images: Much nicer stripes) |
|||
Line 10,904: | Line 10,904: | ||
===Normal Map Effect, Mercator Projection and Deep Zoom Images=== |
===Normal Map Effect, Mercator Projection and Deep Zoom Images=== |
||
The Mandelbrot set is represented by distance estimation and normal maps using NumPy and complex matrices (cf. Arnaud Chéritat: [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Normal_map_effect ''Normal map effect'']). Note that the second derivative (ddZ) grows very fast, so the second method can only be used for small iteration numbers (n <= 400). |
The Mandelbrot set is represented by distance estimation and normal maps using NumPy and complex matrices (cf. Arnaud Chéritat: [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Normal_map_effect ''Normal map effect'']). Note that the second derivative (ddZ) grows very fast, so the second method can only be used for small iteration numbers (n <= 400). See also [https://www.shadertoy.com/view/wtscDX Julia Stripes] on Shadertoy. |
||
<syntaxhighlight lang="python">import numpy as np |
<syntaxhighlight lang="python">import numpy as np |
||
import matplotlib.pyplot as plt |
import matplotlib.pyplot as plt |
||
Line 10,912: | Line 10,912: | ||
direction, height = 45, 1.5 # direction and height of the incoming light |
direction, height = 45, 1.5 # direction and height of the incoming light |
||
stripes, damping = 5.0, 2.0 # stripe density and damping parameter |
|||
v = np.exp(direction / 180 * np.pi * 1j) # unit 2D vector in this direction |
|||
x = np.linspace(0, 2, num=d+1) |
x = np.linspace(0, 2, num=d+1) |
||
Line 10,921: | Line 10,921: | ||
Z, dZ, ddZ = np.zeros_like(C), np.zeros_like(C), np.zeros_like(C) |
Z, dZ, ddZ = np.zeros_like(C), np.zeros_like(C), np.zeros_like(C) |
||
D, T = np.zeros(C.shape), np.zeros(C.shape) |
D, S, T = np.zeros(C.shape), np.zeros(C.shape), np.zeros(C.shape) |
||
for k in range(n): |
for k in range(n): |
||
M = Z.real ** 2 + Z.imag ** 2 < r ** 2 |
M = Z.real ** 2 + Z.imag ** 2 < r ** 2 |
||
S[M], T[M] = S[M] + np.sin(stripes * np.angle(Z[M])), T[M] + 1 |
|||
Z[M], dZ[M], ddZ[M] = Z[M] ** 2 + C[M], 2 * Z[M] * dZ[M] + 1, 2 * (dZ[M] ** 2 + Z[M] * ddZ[M]) |
Z[M], dZ[M], ddZ[M] = Z[M] ** 2 + C[M], 2 * Z[M] * dZ[M] + 1, 2 * (dZ[M] ** 2 + Z[M] * ddZ[M]) |
||
Line 10,934: | Line 10,935: | ||
N = abs(Z) > 2 # normal map effect 1 (potential function) |
N = abs(Z) > 2 # normal map effect 1 (potential function) |
||
P, Q = S[N] / T[N], (S[N] + np.sin(stripes * np.angle(Z[N]))) / (T[N] + 1) |
|||
F = 1 - np.log2(np.log(np.abs(Z[N])) / np.log(r)) |
|||
H = P + (Q - P) * F * F * (3 - 2 * F) # hermite interpolation |
|||
U = Z[N] / dZ[N] # normal vectors to the equipotential lines |
U = Z[N] / dZ[N] # normal vectors to the equipotential lines |
||
U, |
U, v = U / abs(U), np.exp(direction / 180 * np.pi * 1j) # unit normal vectors and unit 2D vector |
||
D[N] = np.maximum((U.real * v.real + U.imag * v.imag + (1 + H / damping) * height) / (1 + height), 0) |
|||
plt.imshow( |
plt.imshow(D ** 1.0, cmap=plt.cm.bone, origin="lower") |
||
plt.savefig("Mandelbrot_normal_map_1.png", dpi=200) |
plt.savefig("Mandelbrot_normal_map_1.png", dpi=200) |
||
N = abs(Z) > 2 # normal map effect 2 (distance estimation) |
N = abs(Z) > 2 # normal map effect 2 (distance estimation) |
||
U = Z[N] * dZ[N] * ((1 + np.log(abs(Z[N]))) * np.conj(dZ[N] ** 2) - np.log(abs(Z[N])) * np.conj(Z[N] * ddZ[N])) |
U = Z[N] * dZ[N] * ((1 + np.log(abs(Z[N]))) * np.conj(dZ[N] ** 2) - np.log(abs(Z[N])) * np.conj(Z[N] * ddZ[N])) |
||
U = U / abs(U) # unit normal vectors |
U, v = U / abs(U), np.exp(direction / 180 * np.pi * 1j) # unit normal vectors and unit 2D vector |
||
D[N] = np.maximum((U.real * v.real + U.imag * v.imag + height) / (1 + height), 0) |
|||
plt.imshow( |
plt.imshow(D ** 1.0, cmap=plt.cm.afmhot, origin="lower") |
||
plt.savefig("Mandelbrot_normal_map_2.png", dpi=200)</syntaxhighlight> |
plt.savefig("Mandelbrot_normal_map_2.png", dpi=200)</syntaxhighlight> |
||