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 :smiley:

  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[2] - x[1]) / 2
    δy = (y[2] - y[1]) / 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)
        mesh!(ax, recmesh; color=cmap2[idx, idy], shading=false)
    end
    fig
end
test3dBars()

You should use meshscatter for this. See https://github.com/JuliaPlots/Makie.jl/issues/624.

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 · MakieOrg/Makie.jl · GitHub

function test3dBars()
    x = y= 1:10
    z = rand(10,10)
    δx = (x[2] - x[1]) / 2
    δy = (y[2] - y[1]) / 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[3], 0) for p in coordinates(recmesh)] # normalize this so zmax = 1
        recmesh = GeometryBasics.Mesh(
            meta(coordinates(recmesh); normals=normals(recmesh), uv = uvs), 
            faces(recmesh)
        )
        mesh!(ax, recmesh; color=texture, shading=false)
    end
    fig
end
test3dBars()

A way to merge all Rect3 meshes?

GeometryBasics implements merge(meshes)

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:
https://github.com/JuliaPlots/Makie.jl/pull/1406