Skip to content

Commit

Permalink
Physically Based Bloom Completely Added
Browse files Browse the repository at this point in the history
  • Loading branch information
AEspinosaDev committed Dec 5, 2024
1 parent 72a1d5c commit 52fb411
Show file tree
Hide file tree
Showing 16 changed files with 244 additions and 210 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ The main feautures of the library are:
- Multipass (depth pass for shadows, SSAO and post-processing).
- Vulkan object and functionality abstraction.
- IBL.
- Physically Based Bloom.
- Simple to use user interface.
- Easy to distribute source code.
- Global Illumination with Voxel Cone Tracing (wip)

This project is a work in progress. It has a long way until becoming a decent library, there are no fancy features for now, but all the basics are here. Eventually, with time, I will be adding more advanced functionality.

Expand Down
6 changes: 3 additions & 3 deletions examples/raytracing/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ void Application::setup_gui() {
m_interface.scene = new Tools::SceneExplorerWidget(m_scene);
explorerPanel->add_child(m_interface.scene);
explorerPanel->add_child(new Tools::Space());
explorerPanel->add_child(new Tools::RendererSettingsWidget(m_renderer));
explorerPanel->add_child(new Tools::DeferredRendererWidget(static_cast<Systems::DeferredRenderer*>(m_renderer)));
explorerPanel->add_child(new Tools::ControllerWidget(m_controller));
explorerPanel->add_child(new Tools::Separator());
explorerPanel->add_child(new Tools::TextLine(" Application average"));
Expand Down Expand Up @@ -214,9 +214,9 @@ void Application::update() {
float _z = light->get_position().x * sin(rotationAngle) + light->get_position().z * cos(rotationAngle);

light->set_position({_x, light->get_position().y, _z});
static_cast<UnlitMaterial*>(static_cast<Mesh*>(light->get_children().front())->get_material(0))
->set_color({light->get_color(), 1.0f});
}
static_cast<UnlitMaterial*>(static_cast<Mesh*>(light->get_children().front())->get_material(0))
->set_color({light->get_color() * light->get_intensity(), 1.0f});

m_interface.object->set_object(m_interface.scene->get_selected_object());
}
Expand Down
33 changes: 28 additions & 5 deletions include/engine/core/passes/bloom_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ VULKAN_ENGINE_NAMESPACE_BEGIN

namespace Core {

/*
Physically Based Bloom Pass.
The method that inspired this article was presented at ACM Siggraph in 2014 by Jorge Jimenez for Call of Duty: Advanced
Warfare.
The algorithm follows this recipe:
- Run a shader which downsamples (downscales) the HDR buffer containing per-pixel color with light and shadows applied.
This shader is run a fixed number of times to continually produce a smaller image, each time with half resolution in
both X and Y axes.
- We then run a small 3x3 filter kernel on each downsampled image, and progressively upsample them until we reach image
A (first downsampled image).
- Finally, we mix the overall bloom contribution into the HDR source image, with a strong bias towards the HDR source.
*/
class BloomPass : public BasePass
{
protected:
Expand All @@ -23,10 +37,14 @@ class BloomPass : public BasePass

Graphics::DescriptorSet m_imageDescriptorSet;

const uint32_t MIPMAP_LEVELS = 6;
const uint32_t MIPMAP_LEVELS = 6;

// Settings
float m_bloomStrength = 0.05f;

// Resources
Graphics::Image m_originalImage;
Graphics::Image m_brightImage;

Graphics::Image m_bloomImage;
std::vector<Graphics::Image> m_bloomMipmaps;

Expand All @@ -36,6 +54,13 @@ class BloomPass : public BasePass
, m_vignette(vignette) {
}

inline float get_bloom_strength() const {
return m_bloomStrength;
}
inline void set_bloom_strength(float st) {
m_bloomStrength = st;
}

void setup_attachments(std::vector<Graphics::Attachment>& attachments,
std::vector<Graphics::SubPassDependency>& dependencies);

Expand All @@ -48,10 +73,8 @@ class BloomPass : public BasePass
void connect_to_previous_images(std::vector<Graphics::Image> images);

void update();

void cleanup();


void cleanup();
};

} // namespace Core
Expand Down
6 changes: 3 additions & 3 deletions include/engine/core/scene/light.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Light : public Object3D
static uint16_t m_nonRaytraceCount;

public:
Light(std::string name, LightType type, Vec3 color = Vec3(1.0f, 1.0f, 1.0f), float intensity = 1.0f)
Light(std::string name, LightType type, Vec3 color = Vec3(1.0f, 1.0f, 1.0f), float intensity = 5.0f)
: Object3D(name, ObjectType::LIGHT)
, m_color(color)
, m_intensity(intensity)
Expand Down Expand Up @@ -179,7 +179,7 @@ class PointLight : public Light
static int m_instanceCount;

public:
PointLight(Vec3 color = Vec3(1.0f, 1.0f, 1.0f), float intensity = 1.0f)
PointLight(Vec3 color = Vec3(1.0f, 1.0f, 1.0f), float intensity = 5.0f)
: Light("Point Light #" + std::to_string(PointLight::m_instanceCount), LightType::POINT, color, intensity)
, m_effectArea(12.0f) {
PointLight::m_instanceCount++;
Expand All @@ -204,7 +204,7 @@ class DirectionalLight : public Light
static int m_instanceCount;

public:
DirectionalLight(Vec3 direction, Vec3 color = Vec3(1.0f, 1.0f, 1.0f), float intensity = 1.0f)
DirectionalLight(Vec3 direction, Vec3 color = Vec3(1.0f, 1.0f, 1.0f), float intensity = 5.0f)
: Light("Directional Light#" + std::to_string(DirectionalLight::m_instanceCount),
LightType::DIRECTIONAL,
color,
Expand Down
16 changes: 16 additions & 0 deletions include/engine/systems/renderers/deferred.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,27 @@ class DeferredRenderer : public BaseRenderer
, m_shadowQuality(shadowQuality) {
}

inline ShadowResolution get_shadow_quality() const {
return m_shadowQuality;
}
inline void set_shadow_quality(ShadowResolution quality) {
m_shadowQuality = quality;
if (m_initialized)
m_updateShadows = true;
}
inline float get_bloom_strength() const {
if (m_passes[BLOOM_PASS])
{
return static_cast<Core::BloomPass*>(m_passes[BLOOM_PASS])->get_bloom_strength();
}
return 0.0f;
}
inline void set_bloom_strength(float st) {
if (m_passes[BLOOM_PASS])
{
static_cast<Core::BloomPass*>(m_passes[BLOOM_PASS])->set_bloom_strength(st);
}
}

protected:
virtual void on_before_render(Core::Scene* const scene);
Expand Down
40 changes: 30 additions & 10 deletions include/engine/tools/renderer_widget.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,52 @@
#ifndef REND_WIDGET_H
#define REND_WIDGET_H

#include <engine/systems/renderers/deferred.h>
#include <engine/systems/renderers/forward.h>
#include <engine/systems/renderers/renderer.h>
#include <engine/tools/widgets.h>

VULKAN_ENGINE_NAMESPACE_BEGIN

namespace Tools
{
namespace Tools {

class RendererSettingsWidget : public Widget
{

protected:
Systems::BaseRenderer *m_renderer;
virtual void render();
Systems::BaseRenderer* m_renderer;
virtual void render();

public:
RendererSettingsWidget(Systems::BaseRenderer* r)
: Widget(ImVec2(0, 0), ImVec2(0, 0))
, m_renderer(r) {
}

inline Systems::BaseRenderer* get_renderer() const {
return m_renderer;
}
inline void set_renderer(Systems::BaseRenderer* r) {
m_renderer = r;
}
};
class DeferredRendererWidget : public Widget
{

protected:
Systems::DeferredRenderer* m_renderer;
virtual void render();

public:
RendererSettingsWidget(Systems::BaseRenderer *r) : Widget(ImVec2(0, 0), ImVec2(0, 0)), m_renderer(r)
{
DeferredRendererWidget(Systems::DeferredRenderer* r)
: Widget(ImVec2(0, 0), ImVec2(0, 0))
, m_renderer(r) {
}

inline Systems::BaseRenderer *get_renderer() const
{
inline Systems::DeferredRenderer* get_renderer() const {
return m_renderer;
}
inline void set_renderer(Systems::BaseRenderer *r)
{
inline void set_renderer(Systems::DeferredRenderer* r) {
m_renderer = r;
}
};
Expand Down
58 changes: 16 additions & 42 deletions resources/shaders/compute/downsample.glsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#shader compute
#version 450
// This shader performs downsampling on a texture,
// as taken from Call Of Duty method, presented at ACM Siggraph 2014.

layout(local_size_x = 32, local_size_y = 32) in;
layout(local_size_x = 16, local_size_y = 16) in;

layout(set = 0, binding = 0) uniform sampler2D srcImage;
layout(set = 0, binding = 1, r32f) uniform image2D mips[6];
Expand All @@ -11,35 +13,7 @@ layout(push_constant) uniform Mipmap {
int dstLevel;
} mip;

// #define SAMPLE_TEXEL(img,coord) ()

// vec3 bilinearSample(ivec2 texCoord, vec2 offset) {
// // Fractional part of the offset
// vec2 frac = fract(offset);

// // Four neighboring texels
// vec3 c00;
// vec3 c10;
// vec3 c01;
// vec3 c11;
// if(mip.srcLevel>0){
// c00 = imageLoad(srcImage, texCoord).rgb;
// c10 = imageLoad(srcImage, texCoord + ivec2(1, 0)).rgb;
// c01 = imageLoad(srcImage, texCoord + ivec2(0, 1)).rgb;
// c11 = imageLoad(srcImage, texCoord + ivec2(1, 1)).rgb;
// else{
// c00 = texelFetch(srcImage, texCoord).rgb;
// c10 = texelFetch(srcImage, texCoord + ivec2(1, 0)).rgb;
// c01 = texelFetch(srcImage, texCoord + ivec2(0, 1)).rgb;
// c11 = texelFetch(srcImage, texCoord + ivec2(1, 1)).rgb;
// }
// // Bilinear interpolation
// vec3 interpX0 = mix(c00, c10, frac.x); // Horizontal interpolation at row 0
// vec3 interpX1 = mix(c01, c11, frac.x); // Horizontal interpolation at row 1
// vec3 result = mix(interpX0, interpX1, frac.y); // Vertical interpolation

// return result;
// }
#define EDGE_CLAMP(coords) (clamp(coords ,ivec2(0.0), mip.srcLevel > 0 ? ivec2(imageSize(mips[mip.srcLevel]).xy) : ivec2(textureSize(srcImage,0).xy)))


void main() {
Expand All @@ -58,22 +32,22 @@ void main() {
if(mip.srcLevel==0){

// Sample 13 neighboring texels around the current texel
vec3 a = texelFetch(srcImage, srcCoord - ivec2(offset2.x, -offset2.y), 0).rgb;
vec3 b = texelFetch(srcImage, srcCoord - ivec2(0, -offset2.y), 0).rgb;
vec3 c = texelFetch(srcImage, srcCoord - ivec2(-offset2.x, -offset2.y), 0).rgb;
vec3 a = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(offset2.x, -offset2.y)), 0).rgb;
vec3 b = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(0, -offset2.y)), 0).rgb;
vec3 c = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(-offset2.x, -offset2.y)), 0).rgb;

vec3 d = texelFetch(srcImage, srcCoord - ivec2(offset2.x, 0), 0).rgb;
vec3 d = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(offset2.x, 0)), 0).rgb;
vec3 e = texelFetch(srcImage, srcCoord, 0).rgb; // Current texel
vec3 f = texelFetch(srcImage, srcCoord - ivec2(-offset2.x, 0), 0).rgb;
vec3 f = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(-offset2.x, 0)), 0).rgb;

vec3 g = texelFetch(srcImage, srcCoord - ivec2(offset2.x, offset2.y), 0).rgb;
vec3 h = texelFetch(srcImage, srcCoord - ivec2(0, offset2.y), 0).rgb;
vec3 i = texelFetch(srcImage, srcCoord - ivec2(-offset2.x, offset2.y), 0).rgb;
vec3 g = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(offset2.x, offset2.y)), 0).rgb;
vec3 h = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(0, offset2.y)), 0).rgb;
vec3 i = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(-offset2.x, offset2.y)), 0).rgb;

vec3 j = texelFetch(srcImage, srcCoord - ivec2(offset1.x, -offset1.y), 0).rgb;
vec3 k = texelFetch(srcImage, srcCoord - ivec2(-offset1.x, -offset1.y), 0).rgb;
vec3 l = texelFetch(srcImage, srcCoord - ivec2(offset1.x, offset1.y), 0).rgb;
vec3 m = texelFetch(srcImage, srcCoord - ivec2(-offset1.x, offset1.y), 0).rgb;
vec3 j = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(offset1.x, -offset1.y)), 0).rgb;
vec3 k = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(-offset1.x, -offset1.y)), 0).rgb;
vec3 l = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(offset1.x, offset1.y)), 0).rgb;
vec3 m = texelFetch(srcImage, EDGE_CLAMP(srcCoord - ivec2(-offset1.x, offset1.y)), 0).rgb;

// texelColor = texelFetch(srcImage, ivec2(dstCoord * 2), 0).rgb;
texelColor = e*0.125; // ok
Expand Down
22 changes: 13 additions & 9 deletions resources/shaders/compute/upsample.glsl
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#shader compute
#version 450
// This shader performs upsampling on a texture,
// as taken from Call Of Duty method, presented at ACM Siggraph 2014.

layout(local_size_x = 32, local_size_y = 32) in;
layout(local_size_x = 16, local_size_y = 16) in;

layout(set = 0, binding = 1, r32f) uniform image2D mips[6];

Expand All @@ -10,6 +12,7 @@ layout(push_constant) uniform Mipmap {
int dstLevel;
} mip;

#define EDGE_CLAMP(coords,size) (clamp(coords ,ivec2(0.0),size))

void main() {
ivec2 dstCoord = ivec2(gl_GlobalInvocationID.xy);
Expand All @@ -23,18 +26,19 @@ void main() {
// g - h - i
ivec2 offsetX = ivec2(1, 0); // Horizontal offset (1 texel in x)
ivec2 offsetY = ivec2(0, 1); // Vertical offset (1 texel in y)
ivec2 pixelSize = imageSize(mips[mip.srcLevel]).xy;

vec3 a = imageLoad(mips[mip.srcLevel], srcCoord - offsetX + offsetY).rgb;
vec3 b = imageLoad(mips[mip.srcLevel], srcCoord + offsetY).rgb;
vec3 c = imageLoad(mips[mip.srcLevel], srcCoord + offsetX + offsetY).rgb;
vec3 a = imageLoad(mips[mip.srcLevel], EDGE_CLAMP(srcCoord - offsetX + offsetY,pixelSize)).rgb;
vec3 b = imageLoad(mips[mip.srcLevel], EDGE_CLAMP(srcCoord + offsetY,pixelSize)).rgb;
vec3 c = imageLoad(mips[mip.srcLevel], EDGE_CLAMP(srcCoord + offsetX + offsetY,pixelSize)).rgb;

vec3 d = imageLoad(mips[mip.srcLevel], srcCoord - offsetX).rgb;
vec3 d = imageLoad(mips[mip.srcLevel], EDGE_CLAMP(srcCoord - offsetX,pixelSize)).rgb;
vec3 e = imageLoad(mips[mip.srcLevel], srcCoord).rgb; // Center texel
vec3 f = imageLoad(mips[mip.srcLevel], srcCoord + offsetX).rgb;
vec3 f = imageLoad(mips[mip.srcLevel], EDGE_CLAMP(srcCoord + offsetX,pixelSize)).rgb;

vec3 g = imageLoad(mips[mip.srcLevel], srcCoord - offsetX - offsetY).rgb;
vec3 h = imageLoad(mips[mip.srcLevel], srcCoord - offsetY).rgb;
vec3 i = imageLoad(mips[mip.srcLevel], srcCoord + offsetX - offsetY).rgb;
vec3 g = imageLoad(mips[mip.srcLevel], EDGE_CLAMP(srcCoord - offsetX - offsetY,pixelSize)).rgb;
vec3 h = imageLoad(mips[mip.srcLevel], EDGE_CLAMP(srcCoord - offsetY,pixelSize)).rgb;
vec3 i = imageLoad(mips[mip.srcLevel], EDGE_CLAMP(srcCoord + offsetX - offsetY,pixelSize)).rgb;

// Apply weighted distribution, by using a 3x3 tent filter:
// 1 | 1 2 1 |
Expand Down
7 changes: 3 additions & 4 deletions resources/shaders/deferred/composition.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -184,11 +184,10 @@ void main()

outColor = vec4(color,1.0);

// check whether result is higher than some threshold, if so, output as bloom threshold color
float brightness = dot(color*5, vec3(0.2126, 0.7152, 0.0722));

// check whether result is higher than some threshold, if so, output as bloom threshold color
float brightness = dot(color, vec3(0.2126, 0.7152, 0.0722));
if(brightness > 1.0)
outBrightColor = vec4(color*5, 1.0);
outBrightColor = vec4(color, 1.0);
else
outBrightColor = vec4(0.0, 0.0, 0.0, 1.0);

Expand Down
6 changes: 5 additions & 1 deletion resources/shaders/misc/bloom.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,15 @@ layout(set = 0, binding = 3) uniform sampler2D bloomImage; //F32

layout(location = 0) out vec4 outputImage;

layout(push_constant) uniform Settings {
float bloomStrenght;
} settings;


void main()
{
vec3 hdrColor = texture(srcImage, v_uv).rgb;
vec3 bloomColor = texture(bloomImage, v_uv).rgb;
outputImage = vec4(mix(hdrColor, bloomColor, 0.05),1.0);
outputImage = vec4(mix(hdrColor, bloomColor, settings.bloomStrenght),1.0);
// outputImage = vec4(hdrColor,1.0);
}
11 changes: 9 additions & 2 deletions resources/shaders/misc/tonemapping.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,15 @@ layout(set = 0, binding = 0) uniform sampler2D inputImage;
layout(location = 0) out vec4 outputImage;



void main()
{
// outputImage = vec4(reindhartTonemap(texture(inputImage,v_uv).rgb),1.0);
outputImage = vec4(texture(inputImage,v_uv).rgb,1.0); //WIP
vec3 result = texture(inputImage,v_uv).rgb;
result = vec3(1.0) - exp(-result * 1.0);

// // also gamma correct while we're at it
// const float GAMMA = 2.2;
// result = pow(result, vec3(1.0 / GAMMA));

outputImage = vec4(result,1.0); //WIP
}
Loading

0 comments on commit 52fb411

Please sign in to comment.