MakieOrg / Makie.jl

Interactive data visualizations and plotting in Julia
https://docs.makie.org/stable
MIT License
2.43k stars 312 forks source link

BoundsError in `recordframe!` with WGLMakie #3961

Closed baggepinnen closed 6 hours ago

baggepinnen commented 5 months ago

When creating animations, I can use GLMakie or CairoMakie without problems, but with WGLMakie I get

ERROR: BoundsError: attempt to access 600×450 Array{RGB{N0f8},2} with eltype RGB{FixedPointNumbers.N0f8} at index [1:721, 1:541]
Stacktrace:
  [1] throw_boundserror(A::Matrix{RGB{FixedPointNumbers.N0f8}}, I::Tuple{UnitRange{Int64}, UnitRange{Int64}})
    @ Base ./abstractarray.jl:737
  [2] checkbounds
    @ ./abstractarray.jl:702 [inlined]
  [3] view(::Matrix{RGB{FixedPointNumbers.N0f8}}, ::UnitRange{Int64}, ::UnitRange{Int64})
    @ Base ./subarray.jl:184
  [4] recordframe!(io::Makie.VideoStream)
    @ Makie ~/.julia/packages/Makie/We6MY/src/ffmpeg-util.jl:245
  [5] Record(func::Render.var"#72#73"{…}, figlike::Makie.Figure, iter::StepRangeLen{…}; kw_args::@Kwargs{…})
    @ Makie ~/.julia/packages/Makie/We6MY/src/recording.jl:174
  [6] record(func::Function, figlike::Makie.Figure, path::String, iter::StepRangeLen{…}; kw_args::@Kwargs{…})
    @ Makie ~/.julia/packages/Makie/We6MY/src/recording.jl:154
  [7] record
    @ ~/.julia/packages/Makie/We6MY/src/recording.jl:152 [inlined]
  [8] render(model::ODESystem, sol::ODESolution{…}, timevec::Nothing; framerate::Int64, x::Int64, y::Int64, z::Int64, R::Matrix{…}, timescale::Float64, scene::Nothing, filename::String, kwargs::@Kwargs{})
    @ Render ~/.julia/dev/Multibody/ext/Render.jl:114

This code appears sufficient to reproduce

using WGLMakie

fig = Figure(size = (600, 600))
scene = LScene(fig[1, 1], scenekw = (lights = [DirectionalLight(RGBf(1, 1, 1), Vec3f(-1, 0, 0))],)); # scene is an LScene not its contained Scene
t = Observable(1.0)
thing = @lift Sphere(Point3f($t), 1f0)
mesh!(scene, thing, color = :white)
fig
record(fig, "test.gif", 0:0.1:1; framerate=5) do time # figure is used to record
    # @show time
    t[] = time
end

The problem is

    xdim, ydim = size(glnative)
    copy!(view(io.buffer, 1:xdim, 1:ydim), glnative)

where glnative has the wrong size for WGLMakie

ffreyer commented 3 months ago

This is a px_per_unit issue. Don't get it with the example above, but with record(..., px_per_unit = 2.0)

mkitti commented 1 month ago

I encountered this issue on a M1 Mac Studio.

julia> versioninfo()
Julia Version 1.10.5
Commit 6f3fdf7b362 (2024-08-27 14:19 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: macOS (arm64-apple-darwin22.4.0)
  CPU: 10 × Apple M1 Max
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, apple-m1)
Threads: 1 default, 0 interactive, 1 GC (on 8 virtual cores)

The first solution I found was to activate with a screen config setting px_per_unit to 1.

WGLMakie.activate!(; px_per_unit=1)

This works, but produces a lower quality figure display.

The next solution I found was to make Base.size aware of px_per_unit:

Base.size(screen::WGLMakie.Screen) = size(screen.scene) .* Int(screen.config.px_per_unit)
asinghvi17 commented 1 month ago

Hmm, that's an interesting question. Should size(screen) mean number of physical pixels or number of logical pixels?

size(scene) currently means logical pixels, and it should probably stay that way, but the contexts in which you would invoke a screen's size are probably all about output handling, so you might want physical pixels there?

mkitti commented 1 month ago

size is used here: https://github.com/MakieOrg/Makie.jl/blob/e90c042d16b461e67b750e5ce53790e732281dba/src/ffmpeg-util.jl#L263

I suppose one could also do the mulitplication there.

 _xdim, _ydim = size(screen) .* Int(screen.config.px_per_unit)
rayegun commented 4 days ago

Just got this with the Lorenz attractor example on the Makie.jl home page using Pluto. Some students ran into it.