I am looking for a package or a toolchain which allows me to render generative visuals as fast as possible (as for example with processing, p5 or other creative languages).
The reason I would like to use julia is, that my models are written in jl and i prefer not to transport everything to a new language. I am using GLMakie atm, But it is way too slow.
The dream would be to stream the Video to an other app via NDI or Syphon.
thanks! i didnt know that this exists. in this project i do only create a 2 pixel image. so i wont use blender, but for an other one this is an option!
GLMakie can be pretty fast (state of the art even for some things), but there are a couple of things that will make things very slow.
Can you pin down whatās too slow?
using Images
using NearestNeighbors
function voronoiColorMap(
graph;
saving::Bool=true,
outdir::String="output/",
xResolution::Int=1024,
yResolution::Int=1024,
xRange=(-1,1),
yRange=(-1,1),
filename::String="visualization",
stateColors=Dict(1 => RGB(1,0,0), 0 => RGB(0,0,0), -1 => RGB(0,0,1)),
ignoreBoundary::Bool=false
)
# Ensure output directory ends with a slash
outdir = endswith(outdir, "/") ? outdir : outdir * "/"
# Pre-allocate arrays and extract data in one pass
nVertices = nv(graph)
verticesCoord = zeros(Float64, 2, nVertices)
states = zeros(Int, nVertices)
# Extract vertex data in chunks for better cache performance
vertex_chunk_size = 128 # Adjust based on your system's cache size
vertices_list = collect(vertices(graph))
Threads.@threads for chunk_start in 1:vertex_chunk_size:nVertices
chunk_end = min(chunk_start + vertex_chunk_size - 1, nVertices)
for i in chunk_start:chunk_end
v = vertices_list[i]
pos = getVertexPosition(graph, v)
@inbounds verticesCoord[1, i] = pos[1]
@inbounds verticesCoord[2, i] = pos[2]
@inbounds states[i] = Int(getVertexState(graph, v))
end
end
# Build the tree once (outside of any loops)
kdtree = KDTree(verticesCoord)
# Pre-allocate the image array
img = Matrix{RGB{Float64}}(undef, yResolution, xResolution)
# Pre-compute x and y coordinates
xCoords = LinRange(xRange[1], xRange[2], xResolution)
yCoords = LinRange(yRange[1], yRange[2], yResolution)
# Pre-allocate query point array to avoid allocations in the loop
query_point = zeros(Float64, 2)
# Process image in chunks for better cache performance
chunk_size = 128 # Adjust based on your system's cache size
# Create a mapping from state values to colors (avoid dictionary lookup)
state_color_map = [stateColors[-1], stateColors[0], stateColors[1]]
# Use @simd and @inbounds for inner loops when possible
@time Threads.@threads for i_chunk in 1:cld(xResolution, chunk_size)
# Calculate start and end indices for this chunk
i_start = (i_chunk - 1) * chunk_size + 1
i_end = min(i_chunk * chunk_size, xResolution)
for i in i_start:i_end
x = xCoords[i]
query_point[1] = x
for j in 1:yResolution
query_point[2] = yCoords[j]
# Use inrange query if possible to avoid sorting operations
id, dist = knn(kdtree, query_point, 1)
idx = id[1]
# Fast indexing into pre-computed color map
# Transform state (-1, 0, 1) to index (1, 2, 3)
state_idx = states[idx] + 2
@inbounds img[j, i] = state_color_map[state_idx]
end
end
end
if saving
save(outdir * filename * ".png", img)
end
return img
end
I want do to basically some shader type stuff. The vertices with colors are defined and the intermediate pixels have the same coler as its nearest neighbour.
The problem is the second loop, which takes roughly 10 times too long.
PS: Note that this is not anymore my GLMakie implementation. I did something slightly different in that plot.
Hm, its kind of finished, but hold back by a weird bug, which we have fixed once already, ok that bug was really stupid and we already fixed itā¦
I guess we could try to merge it soon!