Real-time graphics rendering (generative art)

Alright, you can try this before the release:

]add MakieCore#sd/shadertoy Makie#sd/shadertoy GLMakie#sd/shadertoy
using GLMakie, MetaGraphsNext, Graphs, NearestNeighbors
function graph_data_matrix(graph)
    n = nv(graph)
    data = Matrix{RGBf}(undef, n, 1)
    for (i, v) in enumerate(vertices(graph))
        pos = graph[Symbol("node$v")].pos
        state = graph[Symbol("node$v")].state
        data[i, 1] = RGBf(pos[1], pos[2], state)
    end
    data
end
shader_code = """
uniform int iPointCount;
uniform vec4 iBounds;

vec4 mainImage(in vec2 fragCoord) {
    vec2 uv = fragCoord / iResolution.xy;
    vec2 worldPos = vec2(
        mix(iBounds.x, iBounds.z, uv.x),
        mix(iBounds.y, iBounds.w, uv.y)
    );

    float minDist = 1e10;
    float state = 0.0;
    for (int i = 0; i < iPointCount; ++i) {
        vec4 p = texelFetch(iChannel0, ivec2(i,0), 0);
        float d = distance(worldPos, p.xy);
        if (d < minDist) {
            minDist = d;
            state = p.z;
        }
    }

    vec3 col = vec3(0.0);
    if (state == 1.0) col = vec3(0.8, 0.52, 0.82);
    else if (state == -1.0) col = vec3(1.0, 0.75, 0.43);

    return vec4(col, 1.0);
}
"""

graph = create2DGrid(20, 20)
randomStates!(graph; states=[-1, 1])
texdata = graph_data_matrix(graph)

shadertoy(shader_code;
    uniforms=Dict(
        :iChannel0 => GLMakie.Sampler(texdata; minfilter=:nearest),
        :iPointCount => nv(graph),
        :iBounds => Vec4f(0, 0, 1, 1),
    )
)

I also added another example:

To fill the whole window you can just do:


s = Scene()
shadertoy!(s, shader_code;
    uniforms=Dict(
        :iChannel0 => GLMakie.Sampler(texdata; minfilter=:nearest),
        :iPointCount => nv(graph),
        :iBounds => Vec4f(0, 0, 1, 1),
    )
)
s

I still need to make updating the sampler easier (there seems to be a bug right now for the normal API), but you can animate it like this for now:

s = Scene()
sampler = GLMakie.Sampler(texdata; minfilter=:nearest)
pl = shadertoy!(s, shader_code;
    uniforms=Dict(
        :iChannel0 => sampler,
        :iPointCount => nv(graph),
        :iBounds => Vec4f(0, 0, 1, 1),
    )
)
screen = display(s)

robj = GLMakie.plot2robjs(screen, pl)[1]
for i in 1:100 
    randomStates!(graph; states=[-1, 1])
    texdata = graph_data_matrix(graph)
    GLMakie.GLAbstraction.update!(robj[:iChannel0], texdata)
    screen.requires_update = true
    sleep(1/30)
end

2 Likes