Closed musm closed 8 years ago
Does the bouncy example help: http://www.glvisualize.com/examples/sprites/#bouncy ? Easiest way to animate is via signals. Usually, you should call view/visualize only one time per object, even if its animated! Be sure to also checkout the performance tips;)
Best, Simon On 19 Mar 2016 22:08, "musmo" notifications@github.com wrote:
Hi Simon, I'm kinda struggling to figure how to use GLVisualize from the docs. I would like to display some points them update their position and update the frame after the position is updated. (Also how can I change the background color?)
I know this isn't really an issue but help is much appreciated
using GLVisualize, GeometryTypes
res = (800,600) window = glscreen(resolution=res)
num = 100 x = res[1]_1/8 + (res[1]_6/8)_rand(Float32,num) y = res[2]_1/8 + (res[2]_6/8)_rand(Float32,num)
a = Point2f0[Point2f0(xi,yi) for (xi,yi) in zip(x,y)] points = visualize((Circle(Point2f0(0),5f0),a))view(points, window)@async renderloop(window)
s = rand(Float32,num) for i in eachindex(x) velx = 0 vely = 0 for j in eachindex(y) dx = x[j] - x[i] dy = y[j] - x[i] distsq = dx_dx + dy_dy + 1 velx = velx + dx/distsq vely = vely + dy/distsq end x[i] = x[i] + velx y[i] = y[i] + vely
# update and draw ellipse/circle a[i] = Point2f0(x[i],y[i]) point = visualize((Circle(Point2f0(0),5f0),a)) view(point, window)
end
— You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub https://github.com/JuliaGL/GLVisualize.jl/issues/78
Thanks for the reference, following it I kinda have something that works, although not exactly what I envisioned.
using GLVisualize, GeometryTypes, Reactive, GLAbstraction, Colors
function main()
res = (800,600)
window = glscreen(resolution=res)
timesignal = loop(linspace(0, 1, 10))
num = 500
x = res[1]*1/10 + (res[1]*8/10)*rand(Float32,num)
y = (res[2]/2)*ones(Float32,num)
s = -1 + 2*rand(Float32,num)
function solve_particles(pos_vel, _)
positions, velocity = pos_vel
for i in eachindex(positions)
velx = 0
vely = 0
posi = positions[i]
for j in eachindex(positions)
posj = positions[j]
dx = posj[1] - posi[1]
dy = posj[2] - posi[2]
distsq = dx*dx + dy*dy + 1
velx = velx - s[j]*dy/distsq
vely = vely + s[j]*dx/distsq
end
positions[i] = Point2f0(posi[1] + velx, posi[2] + vely)
end
positions, velocity
end
# t = const_lift(*, timesignal, 20f0)
# add some color
# color_ramp = colormap("Blues", 50)
# colors = RGBA{Float32}[color_ramp[rand(1:50)] for i=1:num]
start_position = Point2f0[Point2f0(xi,yi) for (xi,yi) in zip(x,y)]
position_velocity = foldp(solve_particles, (start_position, zeros(Float32,num)), timesignal)
circle = HyperSphere(Point2f0(0), 2f0)
vis = visualize((circle, map(first, position_velocity)))
view(vis, window, camera=:orthographic_pixel)
renderloop(window)
end
A couple of questions:
(1) How to set the background color to black
(2) How does timesignal work? Changing its parameters doesn't seem to have any effect...
(3) Although this animates the particles, what I really wanted is for the each update to be drawn on screen, with the particles having some transparency; so that you can see the particle's streak.
(4) What's the recommended workflow? Right now I just call include("script.jl"); main()
to test new ideas.
(5) I don't really understand why solve_particles needs an empty second argument. I tried without, but the line position_velocity = foldp(solve_particles, (start_position, zeros(Float32,num)), timesignal)
keeps crashing if I didn't have it just in the bouncy example.
That looks pretty cool :) If you don't mind, can we add this as an example after we figured everything out?
Give me a second, I'll update your example to address 1-5 ;)
Okay here it is:
using GLVisualize, GeometryTypes, Reactive, GLAbstraction, Colors,GLWindow
# time is not needed for this simulation, but since Reactive calls
# it with the time parameter (in the foldp call in l49), we need to have this signature
function solve_particles(pos_vel_s, time)
solve_particles(pos_vel_s)
end
function solve_particles(pos_vel_s)
positions, velocity, s = pos_vel_s
for i in eachindex(positions)
velx = 0
vely = 0
posi = positions[i]
for j in eachindex(positions)
posj = positions[j]
dx = posj[1] - posi[1]
dy = posj[2] - posi[2]
distsq = dx*dx + dy*dy + 1
velx = velx - s[j]*dy/distsq*10f0
vely = vely + s[j]*dx/distsq*10f0
end
positions[i] = Point2f0(posi[1] + velx, posi[2] + vely)
end
positions, velocity, s
end
"""
This code should be executed only one time per julia session!!
If you accidantly close the window, you can call this again.
"""
function init(res=(800,600))
# giving the window a transparent background color makes it transparent to
# the previous frame. It's arguable, if that's really how things should be,
# but that's how it currently works ;)
window = glscreen(resolution=res, background=RGBA(0,0,0,0))
@async renderloop(window)
window
end
function main(window)
res = widths(window)
# generates a signal which updates every 1/60s and samples a new value from linspace
# if 1 is reached, it will start at 0 again.
timesignal = loop(linspace(0, 1, 10))
num = 500
x = res[1]*1/10 + (res[1]*8/10)*rand(Float32,num)
y = (res[2]/2)*ones(Float32,num)
s = -1 + 2*rand(Float32,num)
start_position = Point2f0[Point2f0(xi,yi) for (xi,yi) in zip(x,y)]
# foldp calls solve_particles with the startvalue, v0, and the argument, timesignal, every time
# time signal updates. https://github.com/JuliaLang/Reactive.jl/blob/master/doc/index.md
# alternatively, you could call foldp like this:
# foldp((v0, t) -> solve_particles(v0), startvalue, timesignal)
position_velocity = foldp(solve_particles, (start_position, zeros(Float32,num), s), timesignal)
circle = HyperSphere(Point2f0(0), 2f0)
# boundingbox is still a very expensive operation, so if you don't need it
# you can simply set it to nothing.
vis = visualize(
(circle, map(first, position_velocity)),
boundingbox=nothing,
color=RGBA{Float32}(1,1,1,0.5),
stroke_color=RGBA{Float32}(0,0,0,0), # stroking with transparent black makes the white edge go away
stroke_width=0.5f0
)
empty!(window.renderlist) # clears the renderlist from previous visualizations, so that you can call main() multiple times
view(vis, window, camera=:orthographic_pixel)
end
#=
workflow in Julia REPL:
> include("simulation.jl")
> window = init()
> main(window)
> redefine main/solve_particles
> include("simulation.jl") # if you have the changes in the file
> main() # call again! If you only changed solve_particles, you don't even have to call main again
=#
for it to work you need to be on master, which involves checking out a few other packages:
Pkg.checkout("GLVisualize")
Pkg.checkout("GLAbstraction")
Pkg.checkout("GLWindow")
Pkg.checkout("GeometryTypes")
As you can see in the bouncy and billboard example, you can use arbitrary Arrays of colors (Images) as particles ;)
By the way, if you have feedback about the API and how signals work, feel free to criticize anything. Nothing is really set in stone yet and I'm always looking forward to improve things!
Hi, thanks very much Simon! It doesn't look bad. I was hoping to update the docs (I can add this example and rearrange the docs to make things easier sometime this week). I have been trying to better understand and learn the API by translating processing codes. To me a lot of things are annoying/confusing at the moment. (e.g. having to specify Float32 in certain places to make them work and the names of objects are kinda criptic: Point2f0 e.g. although this just needs better documentation and clarification on how all the packages work together in harmony and their conventions).
(1) It looks like you set the background to be transparent and that is the only reason why after each update the particles from the previous time remain on screen. For this reason also the line: empty!(window.renderlist)
doesn't actually clear the screen when running main(window)
multiple times (unless you resize the window). Thus the original question remains "Although this animates the particles, what I really wanted is for the each update to be drawn on screen, with the particles having some transparency; so that you can see the particle's streak." This makes in it impossible to have a background color (e.g. red,gray,blue).
(2) can you explain what you mean here
# generates a signal which updates every 1/60s and samples a new value from linspace
# if 1 is reached, it will start at 0 again.
timesignal = loop(linspace(0, 1, 10))
you create a linspace from 0 to 1 using 10 points, how does this translate to 1/60s ? I have tried changing the parameters here and observing their effect, but I wasn't really able to determine how it changes the simulation frame rate and time scale and such...
(3) How can I poll for keypresses?
if window.inputs[:buttons_pressed] == :s
@show "yay"
# save .jpg of current frame
end
(4) Which settings do you reccomend to get good quality/and good performance
Depending on which settings I choose the simulation can be faster/slower. (For 1000 particles, it can be slow surprisingly)
(unrelated) (4) None of the Gadfly examples work. (I get libpango not defined..)
using GLVisualize, GeometryTypes, Reactive, GLAbstraction, Colors, GLWindow
function solve_particles(pos_vel_s, time)
solve_particles(pos_vel_s)
end
function solve_particles(pos_vel_s)
positions, velocity, s = pos_vel_s
for i in eachindex(positions)
velx = 0.0
vely = 0.0
posi = positions[i]
for j in eachindex(positions)
posj = positions[j]
dx = posj[1] - posi[1]
dy = posj[2] - posi[2]
distsq = dx*dx + dy*dy + 1.0
velx = velx - s[j]*dy/distsq
vely = vely + s[j]*dx/distsq
end
positions[i] = Point2f0(posi[1] + velx, posi[2] + vely)
end
positions, velocity, s
end
function init(res=(800,600))
window = glscreen("vortex",resolution=res, background=Gray(0.2))
@async renderloop(window)
window
end
function main(window)
res = widths(window)
timesignal = bounce(linspace(0, 1, 2))
num = 1000
x = res[1]*1/10 + (res[1]*8/10)*rand(num)
y = (res[2]/2)*ones(num)
s = 4*(-1 + 2*rand(num))
start_position = Point2f0[Point2f0(xi,yi) for (xi,yi) in zip(x,y)]
position_velocity = foldp(solve_particles, (start_position, zeros(Float32,num), s), timesignal)
circle = HyperSphere(Point2f0(0), 2f0)
# boundingbox is still a very expensive operation, so if you don't need it
# you can simply set it to nothing.
vis = visualize(
(circle, map(first, position_velocity)),
boundingbox=nothing,
color=RGBA(1,1,1,0.75)
)
empty!(window.renderlist) # clears the renderlist from previous visualizations, so that you can call main() multiple times
view(vis, window, camera=:orthographic_pixel)
end
(1)
silly me, of course this doesn't work as you expect it... Will work on a fix tomorrow!
(2) can you explain what you mean here
You can't really change the speed there. What you can do though is this:
timesignal = Input(0)
while ...
push!(timesignal, new_value)
render_frame(window)
sleep(as_long_as_you_want)
end
(3) How can I poll for keypresses?
map(window.inputs[:unicode_input]) do key
if key == 's'
screenshot(window, path="x.png")
end
end
(4) Which settings do you reccomend to get good quality/and good performance
What kind of quality problems do you have? You shouldn't fix them over these settings, as they shouldn't really influence the quality notably. As you notice, they can heavily influence your performance though. Since I do the anti-aliasing of the particles for every pixel with a non trivial formula, setting hardware anti-aliasing to 8x (which sort of means having 8 times as many pixels per calculation) can make this calculation much much slower.
I'm still a bit surprised, since 1000 particles should always render just fine on a decent gpu... Have you set boundingbox=nothing
?
(5)
I'm not sure what's going on with Gadfly. This is not my issue and hasn't been fixed for ages...
Thank you! Actually if key == 's'
doesn't work since key
is an array. I modified it to:
map(window.inputs[:unicode_input]) do key
if 's' in key
screenshot(window, path="x.jpg")
println("saving screenshow")
end
end
and I added to to the end of main()
(It doesn't work if I add this to init()
)
Is there a way to get just the key not the array?
In any case I have some imagemagick errors I need to fix
julia> WARNING: ErrorException("no encode delegate for this image format
MIFF' @ error/constitute.c/WriteImage/1167")
in error at C:\Users\Mustafa.julia\v0.4\ImageMagick\src\libmagickwand.jl:153
in writeimage at C:\Users\Mustafa.julia\v0.4\ImageMagick\src\libmagickwand.jl:250`
Sorry for the slew of questions!
You can use:
map(window.inputs[:keyboard_buttons]) do kam
key, action, mods = kam
if key = GLFW.KEY_S
...
end
end
callback: https://github.com/JuliaGL/GLWindow.jl/blob/master/src/callbacks.jl#L51 glfw key: https://github.com/JuliaGL/GLFW.jl/blob/master/src/glfw3.jl#L50
ImageMagick is a bit annoying.. You might have some luck with this PR: https://github.com/JuliaIO/ImageMagick.jl/pull/28
Just check it out with git and rebuild with Pkg.build("ImageMagick")
by the way, you need to wrap a preserver(signal)
around signals that are not used and go out of scope (e.g, when you do the map(window.inputs[:keyboard_buttons])
in init)
Regarding (5) turning on FXAA greatly reduced all the jagged edges in the 3D examples. However, the animation is not smooth for this 2D example, with 1000 particles, the particles stutter a bit as they are simulated (it should be buttery smooth for 1000 particles)
Also if you wrap a preserver(signal)
and println()
is used inside I think this hangs up the repl...
Not too sure how to apply this in the current example...
timesignal = Input(0)
while ...
push!(timesignal, new_value)
render_frame(window)
sleep(as_long_as_you_want)
end
Regarding (5) turning on FXAA greatly reduced all the jagged edges in the 3D examples.
Yeah 3D is quite the different case. I'm quite that the quality is so bad, but some decisions made it impossible to activate hardware aliasing and other solutions also don't work that well currently. I have different ideas on how to fix it and at some point I should really get it over with!
Also if you wrap a preserver(signal) and println() is used inside I think this hangs up the repl...
That shouldn't be related, but println
inside signals is still quite problematic :(
Or do you have a reproducible example, where println
only hangs, when preserve is used?
I actually wrote SignalView to better debug signals!
You can do something like this:
# main stays as is
function init(res=(800,600))
# giving the window a transparent background color makes it transparent to
# the previous frame. It's arguable, if that's really how things should be,
# but that's how it currently works ;)
window = glscreen(resolution=res, background=RGBA(0,0,0,0))
timesignal = Signal(0)
speed = Signal(1/60)
@async while isopen(window)
push!(timesignal, 0) # value doesn't matter
render_frame(window)
sleep(value(speed))
end
window, timesignal, speed
end
#workflow in Julia REPL:
#=
include("simulation.jl")
window, t, speed = init()
main(window, t)
#redefine main/solve_particles
include("simulation.jl") # if you have the changes in the file
main() # call again! If you only changed solve_particles, you don't even have to call main again
push!(speed, 1/20) # change speed
=#
Here's the frame cleaning code:
using GLVisualize, GeometryTypes, Reactive, GLAbstraction, Colors,GLWindow, ModernGL
# time is not needed for this simulation, but since Reactive calls
# it with the time parameter (in the foldp call in l49), we need to have this signature
function solve_particles(pos_vel_s, time)
solve_particles(pos_vel_s)
end
function solve_particles(pos_vel_s)
positions, velocity, s = pos_vel_s
for i in eachindex(positions)
velx = 0.0
vely = 0.0
posi = positions[i]
for j in eachindex(positions)
posj = positions[j]
dx = posj[1] - posi[1]
dy = posj[2] - posi[2]
distsq = dx*dx + dy*dy + 1.0
velx = velx - s[j]*dy/distsq
vely = vely + s[j]*dx/distsq
end
positions[i] = Point2f0(posi[1] + velx, posi[2] + vely)
end
positions, velocity, s
end
"""
Clears the image of the window to `color`
"""
function clear_frame!(window, color=RGB(1,0,0))
# this works with every color, even hsl
glClearColor(red(color), green(color), blue(color), 1)
GLWindow.clear_all!(window)
end
"""
Resets the state of a window
"""
function reset!(window, color=RGB(1,0,0))
clear_frame!(window, color)
empty!(window.renderlist)
end
"""
This code should be executed only one time per julia session!!
If you accidantly close the window, you can call this again.
"""
function init(res=(800,600))
# giving the window a transparent background color makes it transparent to
# the previous frame. It's arguable, if that's really how things should be,
# but that's how it currently works ;)
window = glscreen(resolution=res, background=RGBA(0,0,0,0))
timesignal = Signal(0)
speed = Signal(1/60)
glClear(GL_COLOR_BUFFER_BIT)
@async while isopen(window)
push!(timesignal, 0) # value doesn't matter
render_frame(window)
sleep(value(speed))
end
window, timesignal, speed
end
function main(window, timesignal)
res = widths(window)
# generates a signal which updates every 1/60s and samples a new value from linspace
# if 1 is reached, it will start at 0 again.
timesignal = loop(linspace(0, 1, 10))
num = 500
x = res[1]*1/10 + (res[1]*8/10)*rand(Float32,num)
y = (res[2]/2)*ones(Float32,num)
s = -1 + 2*rand(Float32,num)
start_position = Point2f0[Point2f0(xi,yi) for (xi,yi) in zip(x,y)]
# foldp calls solve_particles with the startvalue, v0, and the argument, timesignal, every time
# time signal updates. https://github.com/JuliaLang/Reactive.jl/blob/master/doc/index.md
# alternatively, you could call foldp like this:
# foldp((v0, t) -> solve_particles(v0), startvalue, timesignal)
position_velocity = foldp(solve_particles, (start_position, zeros(Float32,num), s), timesignal)
circle = HyperSphere(Point2f0(0), 2f0)
# boundingbox is still a very expensive operation, so if you don't need it
# you can simply set it to nothing.
vis = visualize(
(circle, map(first, position_velocity)),
boundingbox=nothing,
color=RGBA{Float32}(1,1,1,0.5),
stroke_color=RGBA{Float32}(0,0,0,0), # stroking with transparent black makes the white edge go away
stroke_width=0.5f0
)
# clears the renderlist from previous visualizations, so that you can call main() multiple times
reset!(window)
view(vis, window, camera=:orthographic_pixel)
end
#workflow in Julia REPL:
#=
include("simulation.jl")
window, t, speed = init()
main(window, t)
#redefine main/solve_particles
include("simulation.jl") # if you have the changes in the file
main() # call again! If you only changed solve_particles, you don't even have to call main again
push!(speed, 1/20) # change speed
=#
You might need Pkg.checkout("GLWindow")
Great thank you!
My comments are as follow: (resizing the screen or zooming messes up everything, the tranparancy kinda screws things up)
Regarding the println
issues
@async while isopen(window)
push!(timesignal, 0) # value doesn't matter
render_frame(window)
sleep(value(speed))
end
# preserve(map(window.inputs[:keyboard_buttons]) do kam
# if kam == GLFW.KEY_S
# println("saving screenshot")
# screenshot(window, path="x.jpg")
# end
# end
# )
The first works, but if you type s
the repl doesn't go back to julia>
. The second commented out version doesn't work.
Regarding
function clear_frame!(window, color=RGB(0.2,0.2,0.2))
# this works with every color, even hsl
What do you mean that it works for every color? I tried using color=Gray(0.2)
for example at this won't work since red(), green(),blue()
only work for RGB
and glClearColor
only accepts this for its signature. I think I misunderstood.
BTW how are you creating the GIFS for the docs?
Check out the simulation now :)
using GLVisualize, GeometryTypes, Reactive, GLAbstraction, Colors, GLWindow, ModernGL
# time is not needed for this simulation, but since Reactive calls
# it with the time parameter (in the foldp call in l49), we need to have this signature
function solve_particles(pos_vel_s)
dt = 1.0f0
positions, velocity, s = pos_vel_s
for i in eachindex(positions)
velx = 0.0f0
vely = 0.0f0
posi = positions[i]
for j in eachindex(positions)
posj = positions[j]
dx = posj[1] - posi[1]
dy = posj[2] - posi[2]
distsq = dx*dx + dy*dy + 1f0
velx = velx - s[j]*dy/distsq
vely = vely + s[j]*dx/distsq
end
positions[i] = Point2f0(posi[1] + dt*velx, posi[2] + dt*vely)
end
positions, velocity, s
end
"""
Clears the image of the window to `color`
"""
function clear_frame!(window, color=RGB(0.2,0.2,0.2))
# this works with every color, even hsl
glClearColor(red(color), green(color), blue(color), 1)
GLWindow.clear_all!(window)
end
"""
Resets the state of a window
"""
function reset!(window, color=RGB(0.2,0.2,0.2))
clear_frame!(window, color)
empty!(window.renderlist)
end
"""
This code should be executed only one time per julia session!!
If you accidantly close the window, you can call this again.
"""
function init(res=(800,600))
# giving the window a transparent background color makes it transparent to
# the previous frame. It's arguable, if that's really how things should be,
# but that's how it currently works ;)
window = glscreen("vortex",resolution=res, background=RGBA(0,0,0,0))
timesignal = Signal(0)
speed = Signal(1/30)
glClear(GL_COLOR_BUFFER_BIT)
@async while isopen(window)
push!(timesignal, 0) # value doesn't matter
render_frame(window)
sleep(value(speed))
end
# preserve(map(window.inputs[:keyboard_buttons]) do kam
# if kam == GLFW.KEY_S
# println("saving screenshot")
# screenshot(window, path="x.jpg")
# end
# end
# )
preserve(map(window.inputs[:unicode_input]) do key
if 's' in key
println("saving screenshot")
screenshot(window, path="x.jpg")
end
end
)
window, timesignal, speed
end
function main(window, timesignal)
res = widths(window)
const num = 1000
x = Float32[(res[1]/2.0) + (res[2]/3.5) * sin(i*2*pi/num) for i=0:num-1]
y = Float32[(res[2]/2.0) + (res[2]/3.5) * cos(i*2*pi/num) for i=0:num-1]
# x = res[1]*1/10 + (res[1]*8/10)*rand(Float32,num)
# y = (res[2]/2)*ones(Float32,num)
s = (-1 + 2*rand(Float32,num))
start_position = Point2f0[Point2f0(xi,yi) for (xi,yi) in zip(x,y)]
# foldp calls solve_particles with the startvalue, v0, and the argument, timesignal, every time
# time signal updates. https://github.com/JuliaLang/Reactive.jl/blob/master/doc/index.md
# alternatively, you could call foldp like this:
# foldp((v0, t) -> solve_particles(v0), startvalue, timesignal)
position_velocity = foldp((v0,t) -> solve_particles(v0), (start_position, zeros(Float32,num), s), timesignal)
circle = HyperSphere(Point2f0(0), 1f0)
# boundingbox is still a very expensive operation, so if you don't need it
# you can simply set it to nothing.
vis = visualize(
(circle, map(first, position_velocity)),
boundingbox=nothing,
color=RGBA(1,1,1,0.05)
)
reset!(window)
view(vis, window, camera=:orthographic_pixel)
end
It looks awesome!! I've added it to the examples: http://www.glvisualize.com/examples/sprites/#simulation
If you want to add more comments for other GLVisualize beginners, please just edit this file: https://github.com/JuliaGL/GLVisualize.jl/blob/master/examples/sprites/simulation.jl
My comments are as follow: (resizing the screen or zooming messes up everything, the tranparancy kinda screws things up)
That is sort of to be expected, when rendering to a frame and never clearing it but then re-sizing it. Is this handled better by other frameworks? I guess it wouldn't be the hardest thing in the world to handle it a bit better ;)
I tried using color=Gray(0.2) for example at this won't work since red(), green(),blue() only work for RGB
Sorry, you're right! Seems I overestimated Colors
capabilities a bit :( Should be easy to add though!
BTW how are you creating the GIFS for the docs?
With this: https://github.com/JuliaGL/GLVisualize.jl/blob/master/src/videotool.jl#L6
usage:
frames = []
while isopen(window)
render_frame(window)
push!(frames, screenbuffer(window)) # frames will become pretty big, but otherwise things will stutter
end
create_video(frames, "test.webm", "")
you'll need png2yuv
and vpxenc
... they medium easy to get on windows... Just search for precompiled binaries for them ;)
Thanks a lot! I hope to be working/playing around with GLVisualize and improving the docs soon.
Awesome! I'll help where I can!
Hi Simon, I'm kinda struggling to figure how to use GLVisualize from the docs. I would like to display some points them update their position and update the frame after the position is updated. (Also how can I change the background color?)
I know this isn't really an issue but help is much appreciated