I have two 3D arrays. I would like to make an isosurface from the first one and color it using the values of the second array. As far as I understand, a possible solution would be to construct a mesh for the isosurface (e.g. by marching cubes) and then, using interpolation, calculate the values of the second array at the mesh vertices.
So far I found Makie: Colouring 3D Contours by another Array discussion from where I adopted the following code:
import GLMakie as mak
import Interpolations: linear_interpolation
import MarchingCubes: MC, march
import Meshes
import MeshViz
function mesh_data(vals, isovalue)
mc = MC(vals, Int)
march(mc, isovalue)
return mc
end
xmin, xmax, Nx = -10, 10, 101
ymin, ymax, Ny = -10, 10, 101
zmin, zmax, Nz = -10, 10, 101
x = range(xmin, xmax, Nx)
y = range(ymin, ymax, Ny)
z = range(zmin, zmax, Nz)
G = [zi <= 0 || sqrt(xi^2+yi^2+zi^2) <= 5 ? 1.0 : 0.0 for xi=x, yi=y, zi=z]
F = [cos(sqrt(xi^2+zi^2)) for xi=x, yi=y, zi=z]
# Extract an isosurface of G at isovalue=1
meshes = mesh_data(G, 1)
mesh_points = Meshes.Point3[pt for pt=meshes.vertices]
mesh_tris = Meshes.connect.([Tuple(tri) for tri in meshes.triangles], Meshes.Triangle)
to_SimpleMesh = Meshes.SimpleMesh(mesh_points, mesh_tris)
# Interpolate F to colour by onto the vertex locations
# Marching cubes uses cell indices starting at 0
itp = linear_interpolation((0:Nx-1, 0:Ny-1, 0:Nz-1), F)
F_at_verts = [itp(pt[1], pt[2], pt[3]) for pt=Meshes.coordinates.(to_SimpleMesh.vertices)]
fig = mak.Figure()
ax = mak.Axis3(fig[1,1]; aspect=:data)
mak.plot!(ax, to_SimpleMesh; color=F_at_verts)
mak.display(fig)
which gives the following:
However, this solution uses a deprecated package MeshViz
and I do not understand how I can change the properties of the final plot.
Another related examples are:
However, these examples do not work because Makie does not want to plot the meshes generated there.
Do you know how to realize this isosurface coloring using Makie and currently maintained packages?