Skip to content

Commit

Permalink
add Render step
Browse files Browse the repository at this point in the history
  • Loading branch information
ffreyer committed Dec 24, 2024
1 parent 6cb59f9 commit ed75c73
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 65 deletions.
89 changes: 89 additions & 0 deletions GLMakie/src/postprocessing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,92 @@ end
struct EmptyRenderStep <: AbstractRenderStep end


@enum FilterOptions begin
FilterFalse = 0
FilterTrue = 1
FilterAny = 2
end
compare(val::Bool, filter::FilterOptions) = (filter == FilterAny) || (val == Int(filter))
compare(val::Integer, filter::FilterOptions) = (filter == FilterAny) || (val == Int(filter))

struct RenderPlots <: AbstractRenderStep
framebuffer::GLFramebuffer
targets::Vector{GLuint}
clear::Vector{Pair{Int, Vec4f}} # target index -> color

ssao::FilterOptions
transparency::FilterOptions
fxaa::FilterOptions
end

function RenderPlots(screen, stage)
fb = screen.framebuffer
if stage === :SSAO
return RenderPlots(
fb.fb, fb.render_buffer_ids, [3 => Vec4f(0), 4 => Vec4f(0)],
FilterTrue, FilterFalse, FilterAny)
elseif stage === :FXAA
return RenderPlots(
fb.fb, get_attachment.(Ref(fb), [:color, :objectid]), Pair{Int, Vec4f}[],
FilterFalse, FilterFalse, FilterAny)
elseif stage === :OIT
targets = get_attachment.(Ref(fb), [:HDR_color, :objectid, :OIT_weight])
# HDR_color containing sums clears to 0
# OIT_weight containing products clears to 1
clear = [1 => Vec4f(0), 3 => Vec4f(1)]
return RenderPlots(fb.fb, targets, clear, FilterAny, FilterTrue, FilterAny)
else
error("Incorrect stage = $stage given. Should be :SSAO, :FXAA or :OIT.")
end
end

function id2scene(screen, id1)
# TODO maybe we should use a different data structure
for (id2, scene) in screen.screens
id1 == id2 && return true, scene
end
return false, nothing
end

function run_step(screen, glscene, step::RenderPlots)
# Somehow errors in here get ignored silently!?
try
GLAbstraction.bind(step.framebuffer)

for (idx, color) in step.clear
idx <= length(step.targets) || continue
glDrawBuffer(step.targets[idx])
glClearColor(color...)
glClear(GL_COLOR_BUFFER_BIT)
end

glDrawBuffers(length(step.targets), step.targets)

for (zindex, screenid, elem) in screen.renderlist
should_render = elem.visible &&
compare(elem[:ssao][], step.ssao) &&
compare(elem[:transparency][], step.transparency) &&
compare(elem[:fxaa][], step.fxaa)
should_render || continue

found, scene = id2scene(screen, screenid)
(found && scene.visible[]) || continue

ppu = screen.px_per_unit[]
a = viewport(scene)[]
glViewport(round.(Int, ppu .* minimum(a))..., round.(Int, ppu .* widths(a))...)
render(elem)
end
catch e
@error "Error while rendering!" exception = e
rethrow(e)
end
return
end




# TODO: maybe call this a PostProcessor?
# Vaguely leaning on Vulkan Terminology
struct RenderPass{Name} <: AbstractRenderStep
Expand All @@ -79,6 +165,8 @@ function RenderPass{Name}(framebuffer::GLFramebuffer, passes::Vector{RenderObjec
return RenderPass{Name}(framebuffer, passes, Dict{Symbol, Symbol}())
end



function RenderPass{:OIT}(screen)
@debug "Creating OIT postprocessor"

Expand Down Expand Up @@ -325,6 +413,7 @@ function run_step(screen, glscene, step::RenderPass{:FXAA})
end



# TODO: Could also handle integration with Gtk, CImGui, etc with a dedicated struct
struct BlitToScreen <: AbstractRenderStep
framebuffer::GLFramebuffer
Expand Down
74 changes: 12 additions & 62 deletions GLMakie/src/rendering.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,85 +51,35 @@ function render_frame(screen::Screen; resize_buffers=true)
resize!(fb, round.(Int, ppu .* size(screen.scene))...)
end

# prepare stencil (for sub-scenes)
# clear global buffers
GLAbstraction.bind(fb)
glDrawBuffers(length(fb.render_buffer_ids), fb.render_buffer_ids)
glDrawBuffers(2, get_attachment.(Ref(fb), [:color, :objectid]))
glClearColor(0, 0, 0, 0)
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT)

glDrawBuffer(fb.render_buffer_ids[1])
# draw backgrounds
glDrawBuffer(get_attachment(fb, :color))
setup!(screen)
glDrawBuffers(length(fb.render_buffer_ids), fb.render_buffer_ids)

# render with SSAO
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE)
GLAbstraction.render(screen) do robj
return !Bool(robj[:transparency][]) && Bool(robj[:ssao][])
end
# SSAO
run_step(screen, nothing, screen.render_pipeline[1])
# run SSAO
run_step(screen, nothing, screen.render_pipeline[2])

# render all plots without SSAO and transparency
run_step(screen, nothing, screen.render_pipeline[3])

# render no SSAO
glDrawBuffers(2, [get_attachment(fb, :color), get_attachment(fb, :objectid)])
# render all non ssao
GLAbstraction.render(screen) do robj
return !Bool(robj[:transparency][]) && !Bool(robj[:ssao][])
end

# TRANSPARENT RENDER
# clear sums to 0
glDrawBuffer(get_attachment(fb, :HDR_color))
glClearColor(0, 0, 0, 0)
glClear(GL_COLOR_BUFFER_BIT)
# clear alpha product to 1
glDrawBuffer(get_attachment(fb, :OIT_weight))
glClearColor(1, 1, 1, 1)
glClear(GL_COLOR_BUFFER_BIT)
# draw
glDrawBuffers(3, [get_attachment(fb, :HDR_color), get_attachment(fb, :objectid), get_attachment(fb, :OIT_weight)])
# Render only transparent objects
GLAbstraction.render(screen) do robj
return Bool(robj[:transparency][])
end
run_step(screen, nothing, screen.render_pipeline[4])

# TRANSPARENT BLEND
run_step(screen, nothing, screen.render_pipeline[2])
run_step(screen, nothing, screen.render_pipeline[5])

# FXAA
run_step(screen, nothing, screen.render_pipeline[3])
run_step(screen, nothing, screen.render_pipeline[6])

# transfer everything to the screen
run_step(screen, nothing, screen.render_pipeline[4])

return
end

function id2scene(screen, id1)
# TODO maybe we should use a different data structure
for (id2, scene) in screen.screens
id1 == id2 && return true, scene
end
return false, nothing
end

function GLAbstraction.render(filter_elem_func, screen::Screen)
# Somehow errors in here get ignored silently!?
try
for (zindex, screenid, elem) in screen.renderlist
filter_elem_func(elem)::Bool || continue
run_step(screen, nothing, screen.render_pipeline[7])

found, scene = id2scene(screen, screenid)
found || continue
scene.visible[] || continue
ppu = screen.px_per_unit[]
a = viewport(scene)[]
glViewport(round.(Int, ppu .* minimum(a))..., round.(Int, ppu .* widths(a))...)
render(elem)
end
catch e
@error "Error while rendering!" exception = e
rethrow(e)
end
return
end
9 changes: 6 additions & 3 deletions GLMakie/src/screen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,10 @@ Makie.@noconstprop function empty_screen(debugging::Bool, reuse::Bool, window)
reuse,
)

push!(screen.render_pipeline, RenderPlots(screen, :SSAO))
push!(screen.render_pipeline, EmptyRenderStep())
push!(screen.render_pipeline, RenderPlots(screen, :FXAA))
push!(screen.render_pipeline, RenderPlots(screen, :OIT))
push!(screen.render_pipeline, EmptyRenderStep())
push!(screen.render_pipeline, EmptyRenderStep())
push!(screen.render_pipeline, BlitToScreen(screen))
Expand Down Expand Up @@ -386,9 +389,9 @@ function apply_config!(screen::Screen, config::ScreenConfig; start_renderloop::B
return
end

replace_renderpass!(config.ssao ? RenderPass{:SSAO} : EmptyRenderStep, 1)
replace_renderpass!(config.oit ? RenderPass{:OIT} : EmptyRenderStep, 2)
replace_renderpass!(config.fxaa ? RenderPass{:FXAA} : EmptyRenderStep, 3)
replace_renderpass!(config.ssao ? RenderPass{:SSAO} : EmptyRenderStep, 2)
replace_renderpass!(config.oit ? RenderPass{:OIT} : EmptyRenderStep, 5)
replace_renderpass!(config.fxaa ? RenderPass{:FXAA} : EmptyRenderStep, 6)

# TODO: replace shader programs with lighting to update N_lights & N_light_parameters

Expand Down

0 comments on commit ed75c73

Please sign in to comment.