# 3d bars makie, colors and meshes

Probably, the following could be done without to much effort, but I don’t seem to find the right way to do it 1. A way to merge all Rect3 meshes? Plotting one by one becomes really slow after a while.
2. Add a color gradient to each rectangle as a function of `z`. Namely, the colormap maps each rectangle.

This is the start:

``````using GeometryBasics, GLMakie, ColorSchemes
function test3dBars()
x = y= 1:10
z = rand(10,10)
δx = (x - x) / 2
δy = (y - y) / 2
cbarPal = :Spectral_11
ztmp = (z .- minimum(z)) ./ (maximum(z .- minimum(z)))
cmap = get(colorschemes[cbarPal], ztmp)
cmap2 = reshape(cmap, size(z))
fig = Figure(resolution=(1200, 800), fontsize=26)
ax = Axis3(fig[1, 1]; aspect=(1, 1, 1), elevation=π / 6, perspectiveness=0.5)
for (idx, i) in enumerate(x), (idy, j) in enumerate(y)
rectMesh = FRect3D(Vec3f0(i - δx, j - δy, 0), Vec3f0(2δx, 2δy, z[idx, idy]))
recmesh = GeometryBasics.mesh(rectMesh)
end
fig
end
test3dBars()
``````

2 Likes

You should use meshscatter for this. See Convenience function for 3D barplots · Issue #624 · JuliaPlots/Makie.jl · GitHub.

this kinda fixes the speed issue with meshes. But, I was thinking about meshes because a want each Rect3 or marker in this case to have the colormap gradient (and not just one color per marker).

You should be able to do `color = rand(100), colormap = :viridis` or `color = rand(RGBf, 100)`

Again. That just maps one color per marker. And what i want is a colormap gradient for each marker.

Oh sorry, I read over that part. I don’t think you can get that with `meshscatter` right now.

With `mesh` you could use `mesh!(ax, recmesh; color=last.(coordinates(recmesh)), colormap = :Spectral_11, colorrange = (0, 1), shading=false)` but that just intepolates between two colors:

Alternatively you could work with a texture similar to Issues · JuliaPlots/Makie.jl · GitHub

``````function test3dBars()
x = y= 1:10
z = rand(10,10)
δx = (x - x) / 2
δy = (y - y) / 2
cbarPal = :Spectral_11
texture = reshape(get(colorschemes[cbarPal], 0:0.01:1), 1, 101)
fig = Figure(resolution=(1200, 800), fontsize=26)
ax = Axis3(fig[1, 1]; aspect=(1, 1, 1), elevation=π / 6, perspectiveness=0.5)
for (idx, i) in enumerate(x), (idy, j) in enumerate(y)
rectMesh = FRect3D(Vec3f0(i - δx, j - δy, 0), Vec3f0(2δx, 2δy, z[idx, idy]))
recmesh = GeometryBasics.normal_mesh(rectMesh)
uvs = [Point2f(p, 0) for p in coordinates(recmesh)] # normalize this so zmax = 1
recmesh = GeometryBasics.Mesh(
meta(coordinates(recmesh); normals=normals(recmesh), uv = uvs),
faces(recmesh)
)
end
fig
end
test3dBars()
``````

A way to merge all Rect3 meshes?

GeometryBasics implements `merge(meshes)`

2 Likes

Nice! This is the one! Thanks!. Although, as it is, is still slow if we add more meshes in that way.

Edit: nice merge(meshes) works like a charm and simply passing the texture works nicely. Thanks again!

Is this UV stuff documented anywhere?

I don’t think so? I would say it should be documented in GeometryBasics but there isn’t much there…

A mesh with uv coordinates will have one per vertex. During rendering, the uv coordinates are interpolated from the 3 corners of a triangle face for each fragment (pixel) the fragment shader renders. That coordinate is then used index a texture (image) to get a color for that fragment.

I opened a pr that would allow solution 2 to work with meshscatter:

2 Likes