Mandelbrot set: Difference between revisions
Content added Content deleted
m (Made two small cuts.) |
m (Added comments and explanations about the Stripe Average algorithm.) |
||
Line 8,037: | Line 8,037: | ||
'''Smoothing, Normalization and Distance Estimation''' |
'''Smoothing, Normalization and Distance Estimation''' |
||
This is a translation of the corresponding Python section: see there for more explanations. The ''e^(-|z|)-smoothing'', ''normalized iteration count'' and ''exterior distance estimation'' algorithms are used |
This is a translation of the corresponding Python section: see there for more explanations. The ''e^(-|z|)-smoothing'', ''normalized iteration count'' and ''exterior distance estimation'' algorithms are used, partial antialiasing is used for boundary detection. |
||
<syntaxhighlight lang="julia">using Plots |
<syntaxhighlight lang="julia">using Plots |
||
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200) |
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200) |
||
Line 8,082: | Line 8,082: | ||
'''Normal Map Effect and Stripe Average Coloring''' |
'''Normal Map Effect and Stripe Average Coloring''' |
||
The Mandelbrot set is represented using Normal Maps and Stripe Average Coloring by Jussi Härkönen (cf. Arnaud Chéritat: [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Normal_map_effect ''Normal map effect'']). See also the picture in section [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Mixing_it_all ''Mixing it all''] and [https://www.shadertoy.com/view/wtscDX Julia Stripes] on Shadertoy. |
The Mandelbrot set is represented using Normal Maps and Stripe Average Coloring by Jussi Härkönen (cf. Arnaud Chéritat: [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Normal_map_effect ''Normal map effect'']). See also the picture in section [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Mixing_it_all ''Mixing it all''] and [https://www.shadertoy.com/view/wtscDX Julia Stripes] on Shadertoy. To get a stripe pattern similar to that of Arnaud Chéritat, the stripe density can be increased to 8, cos can be used instead of sin, and the color map can be set to binary instead of bone_1. |
||
<syntaxhighlight lang="julia">using Plots |
<syntaxhighlight lang="julia">using Plots |
||
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200) |
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200) |
||
Line 8,103: | Line 8,103: | ||
for k in 1:n |
for k in 1:n |
||
M = abs.(Z) .< r |
M = abs.(Z) .< r |
||
S[M], T[M] = S[M] .+ |
S[M], T[M] = S[M] .+ sin.(stripes .* 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]) |
||
end |
end |
||
N = abs.(Z) .>= r # normal map effect |
N = abs.(Z) .>= r # basic normal map effect with stripe average coloring (normalized iteration count) |
||
P, Q = S[N] ./ T[N], (S[N] .+ |
P, Q = S[N] ./ T[N], (S[N] .+ sin.(stripes .* angle.(Z[N]))) ./ (T[N] .+ 1) |
||
U, V = Z[N] ./ dZ[N], 1 .+ ( |
U, V = Z[N] ./ dZ[N], 1 .+ (log2.(log.(abs.(Z[N])) ./ log(r)) .* (P .- Q) .+ Q) ./ damping |
||
U, v = U ./ abs.(U), exp(direction / 180 * pi * im) # unit normal vectors |
U, v = U ./ abs.(U), exp(direction / 180 * pi * im) # unit normal vectors (equipotential lines) and light |
||
D[N] = max.((real.(U) .* real(v) .+ imag.(U) .* imag(v) .+ V .* height) ./ (1 + height), 0) |
D[N] = max.((real.(U) .* real(v) .+ imag.(U) .* imag(v) .+ V .* height) ./ (1 + height), 0) |
||
Line 8,116: | Line 8,116: | ||
savefig("Mandelbrot_normal_map_1.png") |
savefig("Mandelbrot_normal_map_1.png") |
||
N = abs.(Z) .> 2 # normal map effect |
N = abs.(Z) .> 2 # advanced normal map effect using second derivatives (exterior distance estimation) |
||
U = Z[N] .* dZ[N] .* ((1 .+ log.(abs.(Z[N]))) .* conj.(dZ[N] .^ 2) .- log.(abs.(Z[N])) .* conj.(Z[N] .* ddZ[N])) |
U = Z[N] .* dZ[N] .* ((1 .+ log.(abs.(Z[N]))) .* conj.(dZ[N] .^ 2) .- log.(abs.(Z[N])) .* conj.(Z[N] .* ddZ[N])) |
||
U, v = U ./ abs.(U), exp(direction / 180 * pi * im) # unit normal vectors |
U, v = U ./ abs.(U), exp(direction / 180 * pi * im) # unit normal vectors (equidistant lines) and light |
||
D[N] = max.((real.(U) .* real(v) .+ imag.(U) .* imag(v) .+ height) ./ (1 + height), 0) |
D[N] = max.((real.(U) .* real(v) .+ imag.(U) .* imag(v) .+ height) ./ (1 + height), 0) |
||
Line 8,133: | Line 8,133: | ||
n, r = 8000, 10000 # number of iterations and escape radius (r > 2) |
n, r = 8000, 10000 # number of iterations and escape radius (r > 2) |
||
a = -.743643887037158704752191506114774 # |
a = -.743643887037158704752191506114774 # https://mathr.co.uk/web/m-location-analysis.html |
||
b = 0.131825904205311970493132056385139 # |
b = 0.131825904205311970493132056385139 # try: a, b, n = -1.748764520194788535, 3e-13, 800 |
||
x = range(0, 2, length=d+1) |
x = range(0, 2, length=d+1) |
||
Line 11,055: | Line 11,055: | ||
'''Normal Map Effect and Stripe Average Coloring''' |
'''Normal Map Effect and Stripe Average Coloring''' |
||
The Mandelbrot set is represented using Normal Maps and Stripe Average Coloring by Jussi Härkönen (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 the picture in section [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Mixing_it_all ''Mixing it all''] and [https://www.shadertoy.com/view/wtscDX Julia Stripes] on Shadertoy. |
The Mandelbrot set is represented using Normal Maps and Stripe Average Coloring by Jussi Härkönen (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 the picture in section [https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Mixing_it_all ''Mixing it all''] and [https://www.shadertoy.com/view/wtscDX Julia Stripes] on Shadertoy. To get a stripe pattern similar to that of Arnaud Chéritat, the stripe density can be increased to 8, cos can be used instead of sin, and the color map can be set to binary instead of bone. |
||
<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 11,076: | Line 11,076: | ||
for k in range(n): |
for k in range(n): |
||
M = abs(Z) < r |
M = abs(Z) < r |
||
S[M], T[M] = S[M] + np. |
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]) |
||
N = abs(Z) >= r # normal map effect |
N = abs(Z) >= r # basic normal map effect with stripe average coloring (normalized iteration count) |
||
P, Q = S[N] / T[N], (S[N] + np. |
P, Q = S[N] / T[N], (S[N] + np.sin(stripes * np.angle(Z[N]))) / (T[N] + 1) |
||
U, V = Z[N] / dZ[N], 1 + ( |
U, V = Z[N] / dZ[N], 1 + (np.log2(np.log(np.abs(Z[N])) / np.log(r)) * (P - Q) + Q) / damping |
||
U, v = U / abs(U), np.exp(direction / 180 * np.pi * 1j) # unit normal vectors |
U, v = U / abs(U), np.exp(direction / 180 * np.pi * 1j) # unit normal vectors (equipotential lines) and light |
||
D[N] = np.maximum((U.real * v.real + U.imag * v.imag + V * height) / (1 + height), 0) |
D[N] = np.maximum((U.real * v.real + U.imag * v.imag + V * height) / (1 + height), 0) |
||
Line 11,088: | Line 11,088: | ||
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 |
N = abs(Z) > 2 # advanced normal map effect using second derivatives (exterior 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, v = U / abs(U), np.exp(direction / 180 * np.pi * 1j) # unit normal vectors |
U, v = U / abs(U), np.exp(direction / 180 * np.pi * 1j) # unit normal vectors (equidistant lines) and light |
||
D[N] = np.maximum((U.real * v.real + U.imag * v.imag + height) / (1 + height), 0) |
D[N] = np.maximum((U.real * v.real + U.imag * v.imag + height) / (1 + height), 0) |
||
Line 11,105: | Line 11,105: | ||
n, r = 8000, 10000 # number of iterations and escape radius (r > 2) |
n, r = 8000, 10000 # number of iterations and escape radius (r > 2) |
||
a = -.743643887037158704752191506114774 # |
a = -.743643887037158704752191506114774 # https://mathr.co.uk/web/m-location-analysis.html |
||
b = 0.131825904205311970493132056385139 # |
b = 0.131825904205311970493132056385139 # try: a, b, n = -1.748764520194788535, 3e-13, 800 |
||
x = np.linspace(0, 2, num=d+1) |
x = np.linspace(0, 2, num=d+1) |