Skip to content
This repository has been archived by the owner on Jul 14, 2021. It is now read-only.

Postprocessing refactor #107

Merged
merged 14 commits into from
Feb 2, 2021
8 changes: 3 additions & 5 deletions src/GLVisualize/assets/shader/fragment_output.frag
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

layout(location=0) out vec4 fragment_color;
layout(location=1) out uvec2 fragment_groupid;
layout(location=2) out vec4 fragment_position;
layout(location=3) out vec4 fragment_normal_occlusion;
{{buffers}}


in vec4 o_view_pos;
in vec3 o_normal;
Expand All @@ -15,7 +15,5 @@ void write2framebuffer(vec4 color, uvec2 id){
fragment_color = color;
// For plot/sprite picking
fragment_groupid = id;
// For SSAO
fragment_position = o_view_pos;
fragment_normal_occlusion.xyz = o_normal;
{{buffer_writes}}
}
26 changes: 26 additions & 0 deletions src/GLVisualize/visualize_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ struct GLVisualizeShader <: AbstractLazyShader
view["GLSL_EXTENSIONS"] = "#extension GL_ARB_conservative_depth: enable"
view["SUPPORTED_EXTENSIONS"] = "#define DETPH_LAYOUT"
end
view["buffers"] = get_buffers()
view["buffer_writes"] = get_buffer_writes()
args = Dict{Symbol, Any}(kw_args)
args[:view] = view
args[:fragdatalocation] = [(0, "fragment_color"), (1, "fragment_groupid")]
Expand Down Expand Up @@ -165,3 +167,27 @@ function visualize(@nospecialize(main), @nospecialize(s), @nospecialize(data))
end
return assemble_shader(data)
end

# Make changes to fragment_output to match what's needed for postprocessing
using ..GLMakie: enable_SSAO
function get_buffers()
if enable_SSAO[]
"""
layout(location=2) out vec4 fragment_position;
layout(location=3) out vec3 fragment_normal_occlusion;
"""
else
""
end
end

function get_buffer_writes()
if enable_SSAO[]
"""
fragment_position = o_view_pos;
fragment_normal_occlusion.xyz = o_normal;
"""
else
""
end
end
5 changes: 5 additions & 0 deletions src/gl_backend.jl
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,15 @@ function get_texture!(atlas)
return tex
end

# TODO
const enable_SSAO = Ref(false)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, with all the issue, it seems to be a good idea to only turn it on when actually used!

const enable_FXAA = Ref(true)

include("GLVisualize/GLVisualize.jl")
using .GLVisualize

include("glwindow.jl")
include("postprocessing.jl")
include("screen.jl")
include("rendering.jl")
include("events.jl")
Expand Down
173 changes: 14 additions & 159 deletions src/glwindow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,146 +8,17 @@ struct SelectionID{T <: Integer} <: FieldVector{2, T}
index::T
end

function draw_fullscreen(vao_id)
glBindVertexArray(vao_id)
glDrawArrays(GL_TRIANGLES, 0, 3)
glBindVertexArray(0)
return
end

struct PostprocessPrerender end

function (sp::PostprocessPrerender)()
glDepthMask(GL_TRUE)
glDisable(GL_DEPTH_TEST)
glDisable(GL_BLEND)
glDisable(GL_CULL_FACE)
return
end

const PostProcessROBJ = RenderObject{PostprocessPrerender}

mutable struct GLFramebuffer
resolution::Node{NTuple{2, Int}}
id::NTuple{2, GLuint}

color::Texture{RGBA{N0f8}, 2}
objectid::Texture{Vec{2, GLushort}, 2}
depth::Texture{GLAbstraction.DepthStencil_24_8, 2}
position::Texture{Vec4f0, 2}
normal_occlusion::Texture{Vec4f0, 2}
ssao_noise::Texture{Vec2f0, 2}

color_luma::Texture{RGBA{N0f8}, 2}

postprocess::NTuple{5, PostProcessROBJ}
buffers::Dict{Symbol, Texture}
render_buffer_ids::Vector{GLuint}
end

Base.size(fb::GLFramebuffer) = size(fb.color) # it's guaranteed, that they all have the same size

loadshader(name) = joinpath(@__DIR__, "GLVisualize", "assets", "shader", name)

rcpframe(x) = 1f0 ./ Vec2f0(x[1], x[2])

"""
Creates a postprocessing render object.
This will transfer the pixels from the color texture of the Framebuffer
to the screen and while at it, it can do some postprocessing (not doing it right now):
E.g fxaa anti aliasing, color correction etc.
"""
function postprocess(
color, position, normal_occlusion, ssao_noise,
objectid, color_luma,
framebuffer_size
)

# SSAO setup
N_samples = 64
lerp_min = 0.1f0
lerp_max = 1.0f0
kernel = map(1:N_samples) do i
n = normalize([2.0rand() .- 1.0, 2.0rand() .- 1.0, rand()])
scale = lerp_min + (lerp_max - lerp_min) * (i / N_samples)^2
v = Vec3f0(scale * rand() * n)
end

# compute occlusion
shader1 = LazyShader(
loadshader("postprocessing/fullscreen.vert"),
loadshader("postprocessing/SSAO.frag"),
view = Dict(
"N_samples" => "$N_samples"
)
)
data1 = Dict{Symbol, Any}(
:position_buffer => position,
:normal_occlusion_buffer => normal_occlusion,
:kernel => kernel,
:noise => ssao_noise,
:noise_scale => map(s -> Vec2f0(s ./ 4.0), framebuffer_size),
:projection => Node(Mat4f0(I)),
:bias => Node(0.025f0),
:radius => Node(0.5f0)
)
pass1 = RenderObject(data1, shader1, PostprocessPrerender(), nothing)
pass1.postrenderfunction = () -> draw_fullscreen(pass1.vertexarray.id)

# it's guaranteed, that they all have the same size
Base.size(fb::GLFramebuffer) = size(fb.buffers[:color])

# blur occlusion and combine with color
shader2 = LazyShader(
loadshader("postprocessing/fullscreen.vert"),
loadshader("postprocessing/SSAO_blur.frag")
)
data2 = Dict{Symbol, Any}(
:normal_occlusion => normal_occlusion,
:color_texture => color,
:ids => objectid,
:inv_texel_size => map(t -> Vec2f0(1f0/t[1], 1f0/t[2]), framebuffer_size),
:blur_range => Node(Int32(2))
)
pass2 = RenderObject(data2, shader2, PostprocessPrerender(), nothing)
pass2.postrenderfunction = () -> draw_fullscreen(pass2.vertexarray.id)


# calculate luma for FXAA
shader3 = LazyShader(
loadshader("postprocessing/fullscreen.vert"),
loadshader("postprocessing/postprocess.frag")
)
data3 = Dict{Symbol, Any}(
:color_texture => color
)
pass3 = RenderObject(data3, shader3, PostprocessPrerender(), nothing)
pass3.postrenderfunction = () -> draw_fullscreen(pass3.vertexarray.id)


# perform FXAA
shader4 = LazyShader(
loadshader("postprocessing/fullscreen.vert"),
loadshader("postprocessing/fxaa.frag")
)
data4 = Dict{Symbol, Any}(
:color_texture => color_luma,
:RCPFrame => lift(rcpframe, framebuffer_size),
)
pass4 = RenderObject(data4, shader4, PostprocessPrerender(), nothing)
pass4.postrenderfunction = () -> draw_fullscreen(pass4.vertexarray.id)


# draw color buffer
shader5 = LazyShader(
loadshader("postprocessing/fullscreen.vert"),
loadshader("postprocessing/copy.frag")
)
data5 = Dict{Symbol, Any}(
:color_texture => color
)
pass5 = RenderObject(data5, shader5, PostprocessPrerender(), nothing)
pass5.postrenderfunction = () -> draw_fullscreen(pass5.vertexarray.id)


return (pass1, pass2, pass3, pass4, pass5)
end

function attach_framebuffer(t::Texture{T, 2}, attachment) where T
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, t.id, 0)
Expand All @@ -160,8 +31,6 @@ function GLFramebuffer(fb_size::NTuple{2, Int})

color_buffer = Texture(RGBA{N0f8}, fb_size, minfilter = :nearest, x_repeat = :clamp_to_edge)
objectid_buffer = Texture(Vec{2, GLushort}, fb_size, minfilter = :nearest, x_repeat = :clamp_to_edge)
position_buffer = Texture(Vec4f0, fb_size, minfilter = :nearest, x_repeat = :clamp_to_edge)
normal_occlusion_buffer = Texture(Vec4f0, fb_size, minfilter = :nearest, x_repeat = :clamp_to_edge)

depth_buffer = Texture(
Ptr{GLAbstraction.DepthStencil_24_8}(C_NULL), fb_size,
Expand All @@ -170,15 +39,8 @@ function GLFramebuffer(fb_size::NTuple{2, Int})
format = GL_DEPTH_STENCIL
)

ssao_noise = Texture(
[normalize(Vec2f0(2.0rand(2) .- 1.0)) for _ in 1:4, __ in 1:4],
minfilter = :nearest, x_repeat = :repeat
)

attach_framebuffer(color_buffer, GL_COLOR_ATTACHMENT0)
attach_framebuffer(objectid_buffer, GL_COLOR_ATTACHMENT1)
attach_framebuffer(position_buffer, GL_COLOR_ATTACHMENT2)
attach_framebuffer(normal_occlusion_buffer, GL_COLOR_ATTACHMENT3)
attach_framebuffer(depth_buffer, GL_DEPTH_ATTACHMENT)
attach_framebuffer(depth_buffer, GL_STENCIL_ATTACHMENT)

Expand All @@ -187,42 +49,35 @@ function GLFramebuffer(fb_size::NTuple{2, Int})


# Second Framebuffer
# postprocessor adds buffers here
color_luma_framebuffer = glGenFramebuffers()
glBindFramebuffer(GL_FRAMEBUFFER, color_luma_framebuffer)

color_luma = Texture(RGBA{N0f8}, fb_size, minfilter=:linear, x_repeat=:clamp_to_edge)
attach_framebuffer(color_luma, GL_COLOR_ATTACHMENT0)

@assert status == GL_FRAMEBUFFER_COMPLETE

glBindFramebuffer(GL_FRAMEBUFFER, 0)
fb_size_node = Node(fb_size)

p = postprocess(
color_buffer, position_buffer, normal_occlusion_buffer, ssao_noise, #occlusion,
objectid_buffer, color_luma,
fb_size_node
buffers = Dict(
:color => color_buffer,
:objectid => objectid_buffer,
:depth => depth_buffer
)

return GLFramebuffer(
fb_size_node,
(render_framebuffer, color_luma_framebuffer),
color_buffer, objectid_buffer, depth_buffer,
position_buffer, normal_occlusion_buffer, ssao_noise,# occlusion,
color_luma,
p
buffers,
[GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1]
)
end

function Base.resize!(fb::GLFramebuffer, window_size)
ws = Int.((window_size[1], window_size[2]))
if ws != size(fb) && all(x-> x > 0, window_size)
resize_nocopy!(fb.color, ws)
resize_nocopy!(fb.objectid, ws)
resize_nocopy!(fb.depth, ws)
resize_nocopy!(fb.position, ws)
resize_nocopy!(fb.normal_occlusion, ws)
resize_nocopy!(fb.color_luma, ws)
for (name, buffer) in fb.buffers
resize_nocopy!(buffer, ws)
end
fb.resolution[] = ws
end
nothing
Expand Down
Loading