diff --git a/engine/core/src/debug.cpp b/engine/core/src/debug.cpp index a4b6172..41e1bf8 100644 --- a/engine/core/src/debug.cpp +++ b/engine/core/src/debug.cpp @@ -109,6 +109,9 @@ void draw_renderer() { ImGui::DragFloat("Min Luminance", &render_options.min_luminance); ImGui::DragFloat("Max Luminance", &render_options.max_luminance); + ImGui::Checkbox("Enable DoF", &render_options.enable_depth_of_field); + ImGui::DragFloat("DoF Strength", &render_options.depth_of_field_strength); + bool should_recompile = false; float render_scale = render_options.render_scale; diff --git a/engine/renderer/include/dofpass.hpp b/engine/renderer/include/dofpass.hpp index 2ec8e78..d6a4bd1 100755 --- a/engine/renderer/include/dofpass.hpp +++ b/engine/renderer/include/dofpass.hpp @@ -15,6 +15,14 @@ public: void render(GFXCommandBuffer* command_buffer, Scene& scene); + GFXTexture* far_field = nullptr; + GFXTexture* normal_field = nullptr; + + GFXFramebuffer* far_framebuffer = nullptr; + GFXFramebuffer* normal_framebuffer = nullptr; + + GFXRenderPass* renderpass = nullptr; + private: Renderer* renderer = nullptr; diff --git a/engine/renderer/include/render_options.hpp b/engine/renderer/include/render_options.hpp index 4ffa1ec..b6599fa 100755 --- a/engine/renderer/include/render_options.hpp +++ b/engine/renderer/include/render_options.hpp @@ -43,6 +43,9 @@ struct RenderOptions { float min_luminance = -8.0f; float max_luminance = 3.0f; + bool enable_depth_of_field = true; + float depth_of_field_strength = 3.0f; + bool dynamic_resolution = false; double render_scale = 1.0f; diff --git a/engine/renderer/src/dofpass.cpp b/engine/renderer/src/dofpass.cpp index 942c039..eb58d77 100755 --- a/engine/renderer/src/dofpass.cpp +++ b/engine/renderer/src/dofpass.cpp @@ -11,6 +11,11 @@ AssetPtr aperture_texture; DoFPass::DoFPass(GFX* gfx, Renderer* renderer) : renderer(renderer) { aperture_texture = assetm->get(file::app_domain / "textures/aperture.png"); + GFXRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.attachments.push_back(GFXPixelFormat::RGBA_32F); + + renderpass = gfx->create_render_pass(renderPassInfo); + const auto extent = renderer->get_render_extent(); GFXShaderConstant width_constant = {}; @@ -24,17 +29,58 @@ DoFPass::DoFPass(GFX* gfx, Renderer* renderer) : renderer(renderer) { create_info.shaders.vertex_path = "dof.vert"; create_info.shaders.vertex_constants = {width_constant, height_constant}; create_info.shaders.fragment_path = "dof.frag"; - create_info.render_pass = renderer->viewportRenderPass; + + create_info.shader_input.bindings = { + {2, GFXBindingType::PushConstant} + }; + + create_info.render_pass = renderpass; + create_info.blending.enable_blending = true; - create_info.blending.src_rgb = GFXBlendFactor::SrcAlpha; - create_info.blending.dst_rgb = GFXBlendFactor::OneMinusSrcAlpha; + create_info.blending.src_rgb = GFXBlendFactor::SrcColor; + create_info.blending.dst_rgb = GFXBlendFactor::One; create_info.blending.src_alpha = GFXBlendFactor::SrcAlpha; - create_info.blending.dst_alpha = GFXBlendFactor::OneMinusSrcAlpha; + create_info.blending.dst_alpha = GFXBlendFactor::One; pipeline = gfx->create_graphics_pipeline(create_info); + + GFXTextureCreateInfo textureInfo = {}; + textureInfo.width = extent.width; + textureInfo.height = extent.height; + textureInfo.format = GFXPixelFormat::RGBA_32F; + textureInfo.usage = GFXTextureUsage::Attachment | GFXTextureUsage::Sampled; + textureInfo.samplingMode = SamplingMode::ClampToEdge; + + normal_field = gfx->create_texture(textureInfo); + far_field = gfx->create_texture(textureInfo); + + GFXFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.render_pass = renderpass; + framebufferInfo.attachments = { normal_field }; + + normal_framebuffer = gfx->create_framebuffer(framebufferInfo); + + framebufferInfo.attachments = { far_field }; + + far_framebuffer = gfx->create_framebuffer(framebufferInfo); } void DoFPass::render(GFXCommandBuffer* command_buffer, Scene&) { + const auto render_extent = renderer->get_render_extent(); + + // render far field + GFXRenderPassBeginInfo beginInfo = {}; + beginInfo.framebuffer = far_framebuffer; + beginInfo.render_pass = renderpass; + + command_buffer->set_render_pass(beginInfo); + + Viewport viewport = {}; + viewport.width = render_extent.width; + viewport.height = render_extent.height; + + command_buffer->set_viewport(viewport); + command_buffer->set_graphics_pipeline(pipeline); command_buffer->bind_texture(renderer->offscreenColorTexture, 0); @@ -43,5 +89,26 @@ void DoFPass::render(GFXCommandBuffer* command_buffer, Scene&) { const auto extent = renderer->get_render_extent(); + Vector4 params(render_options.depth_of_field_strength, 0.0, 0.0, 0.0); + + command_buffer->set_push_constant(¶ms, sizeof(Vector4)); + + command_buffer->draw(0, 4, 0, extent.width * extent.height); + + // render normal field + beginInfo.framebuffer = normal_framebuffer; + + command_buffer->set_render_pass(beginInfo); + + command_buffer->set_graphics_pipeline(pipeline); + + command_buffer->bind_texture(renderer->offscreenColorTexture, 0); + command_buffer->bind_texture(renderer->offscreenDepthTexture, 1); + command_buffer->bind_texture(aperture_texture->handle, 2); + + params.y = 1; + + command_buffer->set_push_constant(¶ms, sizeof(Vector4)); + command_buffer->draw(0, 4, 0, extent.width * extent.height); } diff --git a/engine/renderer/src/renderer.cpp b/engine/renderer/src/renderer.cpp index 215379f..8ff612c 100755 --- a/engine/renderer/src/renderer.cpp +++ b/engine/renderer/src/renderer.cpp @@ -225,7 +225,7 @@ void Renderer::render(Scene* scene, int index) { if(scene != nullptr && hasToRender) { commandbuffer->push_group("Shadow Rendering"); - + shadow_pass->render(commandbuffer, *scene); commandbuffer->pop_group(); @@ -242,7 +242,7 @@ void Renderer::render(Scene* scene, int index) { for(auto& [obj, camera] : cameras) { const int actual_width = render_extent.width / cameras.size(); - camera.perspective = transform::infinite_perspective(radians(camera.fov), static_cast(actual_width) / static_cast(render_extent.height), camera.near); + camera.perspective = transform::perspective(radians(camera.fov), static_cast(actual_width) / static_cast(render_extent.height), 0.1f, 100.0f); camera.view = inverse(scene->get(obj).model); Viewport viewport = {}; @@ -255,7 +255,7 @@ void Renderer::render(Scene* scene, int index) { commandbuffer->push_group("render camera"); render_camera(commandbuffer, *scene, obj, camera, get_render_extent(), continuity); - + commandbuffer->pop_group(); } } @@ -268,6 +268,8 @@ void Renderer::render(Scene* scene, int index) { commandbuffer->pop_group(); + dofPass->render(commandbuffer, *scene); + if(!viewport_mode) { beginInfo.framebuffer = nullptr; beginInfo.render_pass = nullptr; @@ -311,22 +313,35 @@ void Renderer::render(Scene* scene, int index) { commandbuffer->dispatch(1, 1, 1); commandbuffer->set_graphics_pipeline(viewport_mode ? renderToViewportPipeline : postPipeline); - commandbuffer->bind_texture(offscreenColorTexture, 1); + + if(render_options.enable_depth_of_field) + commandbuffer->bind_texture(dofPass->normal_field, 1); + else + commandbuffer->bind_texture(offscreenColorTexture, 1); + commandbuffer->bind_texture(offscreenBackTexture, 2); commandbuffer->bind_texture(smaaPass->blend_texture, 3); - if(auto texture = get_requested_texture(PassTextureType::SelectionSobel)) { + if(auto texture = get_requested_texture(PassTextureType::SelectionSobel)) commandbuffer->bind_texture(texture, 4); - } else { + else commandbuffer->bind_texture(dummyTexture, 4); - } commandbuffer->bind_texture(average_luminance_texture, 5); + + if(render_options.enable_depth_of_field) + commandbuffer->bind_texture(dofPass->far_field, 6); + else + commandbuffer->bind_texture(dummyTexture, 6); PostPushConstants pc; pc.options.x = render_options.enable_aa; pc.options.y = fade; pc.options.z = render_options.exposure; + + if(render_options.enable_depth_of_field) + pc.options.w = 2; + pc.transform_ops.x = (int)render_options.display_color_space; pc.transform_ops.y = (int)render_options.tonemapping; @@ -346,6 +361,7 @@ void Renderer::render(Scene* scene, int index) { commandbuffer->draw(0, 4, 0, 1); + commandbuffer->pop_group(); if(current_screen != nullptr) diff --git a/shaders/dof.frag.glsl b/shaders/dof.frag.glsl index 2470707..cfa01f8 100644 --- a/shaders/dof.frag.glsl +++ b/shaders/dof.frag.glsl @@ -7,16 +7,22 @@ layout(location = 0) out vec4 outColor; layout(rgba32f, binding = 0) uniform image2D color_sampler; layout(binding = 2) uniform sampler2D aperture_sampler; -vec4 fromLinear(vec4 linearRGB) -{ - return pow(linearRGB, vec4(1.0/2.2)); -} +layout(push_constant, binding = 2) uniform readonly PushConstant{ + vec4 params; +}; void main() { - /*if(depth < 0.98) - discard;*/ + // far field mode + if(params.y == 0) { + if(depth < 0.98) + discard; + } + if(inUV.y > 1.0 || inUV.x > 1.0) discard; - outColor = vec4(fromLinear(imageLoad(color_sampler, inPixel)).rgb, 1.0) * texture(aperture_sampler, inUV); + outColor = vec4(imageLoad(color_sampler, inPixel).rgb, 1.0); + if(params.y == 0) { + outColor = outColor * texture(aperture_sampler, inUV); + } } diff --git a/shaders/dof.vert.glsl b/shaders/dof.vert.glsl index 235171f..8024370 100644 --- a/shaders/dof.vert.glsl +++ b/shaders/dof.vert.glsl @@ -7,6 +7,10 @@ layout(location = 2) out float outDepth; layout(binding = 1) uniform sampler2D depth_sampler; +layout(push_constant, binding = 2) uniform readonly PushConstant{ + vec4 params; +}; + void main() { outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); @@ -17,7 +21,12 @@ void main() { outDepth = depth; vec2 pos = vec2(outUV * 2.0 + -1.0); - pos *= 5.0 * depth; + + // far field mode + if(params.y == 0) { + pos *= params.x * depth; + } + pos += vec2(pixel.x, pixel.y); pos *= 2.0 / vec2(width, height); pos += vec2(-1, -1); diff --git a/shaders/post.frag.glsl b/shaders/post.frag.glsl index 8934da6..e025bc8 100755 --- a/shaders/post.frag.glsl +++ b/shaders/post.frag.glsl @@ -24,6 +24,7 @@ layout (binding = 2) uniform sampler2D backSampler; layout (binding = 3) uniform sampler2D blendSampler; layout (binding = 4) uniform sampler2D sobelSampler; layout (binding = 5) uniform sampler2D averageLuminanceSampler; +layout (binding = 6) uniform sampler2D farFieldSampler; float calculate_sobel() { float x = 1.0 / viewport.z; @@ -109,12 +110,18 @@ void main() { return; } + bool enable_dof = options.w == 2; vec3 sceneColor = vec3(0); - if(options.x == 1) // enable AA - sceneColor = SMAANeighborhoodBlendingPS(inUV, inOffset, colorSampler, blendSampler).rgb; - else - sceneColor = texture(colorSampler, inUV).rgb; - + if(enable_dof) { + sceneColor = texture(farFieldSampler, inUV).rgb; + sceneColor += texture(colorSampler, inUV).rgb; + } else { + if(options.x == 1) // enable AA + sceneColor = SMAANeighborhoodBlendingPS(inUV, inOffset, colorSampler, blendSampler).rgb; + else + sceneColor = texture(colorSampler, inUV).rgb; + } + float sobel = 0.0; if(textureSize(sobelSampler, 0).x > 1) sobel = calculate_sobel();