Browse Source

Implemented Physically Based Bloom by downscaling and upscaling the frambuffer using compute shaders while computing luminance with a small lookup kernel
Added bloom pass in the renderer
Added lens dirt texture in the bloom pass
Added support for compute shaders in the renderer (new compute dispatch command buffer and memory barrier types)
Added support for compute shaders in the ShaderLoader
Added support for image texture bindings and their mipmap levels, required by compute shaders
Added more uniforms in the ShaderUniformUpdater
Fixed atmospheric scattering shader producing NaN values when a pixel is closer to camera then Znear (which produced black bars during bloom pass via NaN propagation)
Removed old post-processing passes (bloom, HDR, lens flare and blur)

Paul A 3 years ago
parent
commit
6063c4e7b6

+ 54 - 7
Praxis3D/Data/Maps/componentTest.pmap

@@ -105,22 +105,22 @@
 										"Diffuse":
 										"Diffuse":
 										{
 										{
 											"Filename": "Metal_CleanPaintedWithChips_2k_alb.tga",
 											"Filename": "Metal_CleanPaintedWithChips_2k_alb.tga",
-											"TextureScale": "1.0f, 1.0f"
+											"TextureScale": "100.0f, 100.0f"
 										},
 										},
 										"Normal":
 										"Normal":
 										{
 										{
 											"Filename": "Metal_CleanPaintedWithChips_2k_n.tga",
 											"Filename": "Metal_CleanPaintedWithChips_2k_n.tga",
-											"TextureScale": "1.0f, 1.0f"
+											"TextureScale": "100.0f, 100.0f"
 										},
 										},
 										"Emissive":
 										"Emissive":
 										{
 										{
 											"Filename": "default_emissive.png",
 											"Filename": "default_emissive.png",
-											"TextureScale": "1.0f, 1.0f"
+											"TextureScale": "100.0f, 100.0f"
 										},
 										},
 										"RMHAO":
 										"RMHAO":
 										{
 										{
-											"Filename": "Metal_CleanPaintedWithChips_RMHAO.tga",
-											"TextureScale": "1.0f, 1.0f"
+											"Filename": "Metal_CleanPaintedWithChips_RMHAO3.tga",
+											"TextureScale": "100.0f, 100.0f"
 										}
 										}
 									}
 									}
 								}
 								}
@@ -206,6 +206,53 @@
 				}
 				}
 			},
 			},
 			"Rendering":
 			"Rendering":
+			{
+				"ModelComponent":
+				{
+					"Models":
+					[
+						{
+							"Filename": "sphereNew4.3DS",
+							"Meshes":
+							[
+								{
+									"Index": "0",
+									"AlphaThreshold": "0.0f",
+									"HeightScale": "0.0f",
+									"Materials":
+									{
+										"Diffuse":
+										{
+											"Filename": "test_albedoGold.png",
+											"TextureScale": "1.0f, 1.0f"
+										},
+										"RMHAO":
+										{
+											"Filename": "test1_RM.png",
+											"TextureScale": "1.0f, 1.0f"
+										}
+									}
+								}
+							]
+						}
+					]
+				}
+			}
+		},
+		{
+			"ID": "5",
+			"Name": "Sphere 2",
+			"Parent": "0",
+			"World":
+			{
+				"SpatialComponent":
+				{
+					"LocalPosition": "10.0f, 5.0f, 5.0f",
+					"LocalRotation": "0.0f, 45.0f, 0.0f",
+					"LocalScale": "4.0f, 4.0f, 4.0f"
+				}
+			},
+			"Rendering":
 			{
 			{
 				"ModelComponent":
 				"ModelComponent":
 				{
 				{
@@ -294,7 +341,7 @@
 				{
 				{
 					"Type": "DirectionalLight",
 					"Type": "DirectionalLight",
 					"Color": "1.0f, 0.0f, 0.0f",
 					"Color": "1.0f, 0.0f, 0.0f",
-					"Intensity": "0.2f"
+					"Intensity": "20.0f"
 				}
 				}
 			}
 			}
 		},
 		},
@@ -378,7 +425,7 @@
 				{
 				{
 					"Type": "PointLight",
 					"Type": "PointLight",
 					"Color": "1.0f, 1.0f, 1.0f",
 					"Color": "1.0f, 1.0f, 1.0f",
-					"Intensity": "10.0f"
+					"Intensity": "100.0f"
 				}
 				}
 			}
 			}
 		}
 		}

+ 1 - 0
Praxis3D/Data/Shaders/atmosphericScatteringPass_ground_simple.frag

@@ -511,6 +511,7 @@ vec3 GetSkyRadianceToPoint(
 	// assuming the viewer is in space (or NaN if the view ray does not intersect
 	// assuming the viewer is in space (or NaN if the view ray does not intersect
 	// the atmosphere).
 	// the atmosphere).
 	vec3 view_ray = normalize(p_point - p_cameraPos);
 	vec3 view_ray = normalize(p_point - p_cameraPos);
+	view_ray = vec3(isnan(view_ray.x) ? 0.0000001 : view_ray.x, isnan(view_ray.y) ? 0.0000001 : view_ray.y, isnan(view_ray.z) ? 0.0000001 : view_ray.z);
 	float r = length(p_cameraPos);
 	float r = length(p_cameraPos);
 	float rmu = dot(p_cameraPos, view_ray);
 	float rmu = dot(p_cameraPos, view_ray);
 	float distance_to_top_atmosphere_boundary = -rmu -sqrt(rmu * rmu - r * r + p_atmospherePar.top_radius * p_atmospherePar.top_radius);
 	float distance_to_top_atmosphere_boundary = -rmu -sqrt(rmu * rmu - r * r + p_atmospherePar.top_radius * p_atmospherePar.top_radius);

+ 1 - 0
Praxis3D/Data/Shaders/atmosphericScatteringPass_sky.frag

@@ -643,4 +643,5 @@ void main()
 	
 	
 	//color = vec4(vec3(1.0) - exp(-radiance / atmScatteringParam.m_whitePoint * directionalLight.m_intensity), 1.0);
 	//color = vec4(vec3(1.0) - exp(-radiance / atmScatteringParam.m_whitePoint * directionalLight.m_intensity), 1.0);
 	color = vec4(radiance / atmScatteringParam.m_whitePoint * directionalLight.m_intensity * 1.0, 1.0);
 	color = vec4(radiance / atmScatteringParam.m_whitePoint * directionalLight.m_intensity * 1.0, 1.0);
+	//color = vec4(radiance / atmScatteringParam.m_whitePoint, 1.0);
 }
 }

+ 124 - 0
Praxis3D/Data/Shaders/bloomDownscale.comp

@@ -0,0 +1,124 @@
+#version 460
+
+#define GROUP_SIZE         8
+#define GROUP_THREAD_COUNT (GROUP_SIZE * GROUP_SIZE)
+#define FILTER_SIZE        3
+#define FILTER_RADIUS      (FILTER_SIZE / 2)
+#define TILE_SIZE          (GROUP_SIZE + 2 * FILTER_RADIUS)
+#define TILE_PIXEL_COUNT   (TILE_SIZE * TILE_SIZE)
+
+layout(binding = 0)			 uniform sampler2D inputColorMap;
+layout(rgba16f, binding = 0) uniform writeonly image2D outputColorMap;
+
+uniform vec4  bloomTreshold; // x -> threshold, yzw -> (threshold - knee, 2.0 * knee, 0.25 * knee)
+uniform vec2  texelSize;
+uniform int   mipLevel;
+
+const float epsilon = 1.0e-4;
+
+// Curve = (threshold - knee, knee * 2.0, knee * 0.25)
+vec4 calculateQuadraticThreshold(vec4 p_color, float p_threshold, vec3 p_curve)
+{
+	// Pixel brightness
+    float brightness = max(p_color.r, max(p_color.g, p_color.b));
+
+    // Under-threshold part: quadratic curve
+    float quadCurve = clamp(brightness - p_curve.x, 0.0, p_curve.y);
+    quadCurve = p_curve.z * quadCurve * quadCurve;
+
+    // Combine and apply the brightness response curve
+    p_color *= max(quadCurve, brightness - p_threshold) / max(brightness, epsilon);
+
+    return p_color;
+}
+
+// Calculate Luma of the the color
+float calculateLuma(vec3 p_color)
+{
+    return dot(p_color, vec3(0.2126729, 0.7151522, 0.0721750));
+}
+
+// [Karis2013] proposed reducing the dynamic range before averaging
+vec4 calculateKarisAverage(vec4 p_color)
+{
+    return p_color / (1.0 + calculateLuma(p_color.rgb));
+}
+
+// Local Data Storage buffers
+shared float sharedBufferR[TILE_PIXEL_COUNT];
+shared float sharedBufferG[TILE_PIXEL_COUNT];
+shared float sharedBufferB[TILE_PIXEL_COUNT];
+
+void storeLDS(int p_idx, vec4 p_color)
+{
+    sharedBufferR[p_idx] = p_color.r;
+    sharedBufferG[p_idx] = p_color.g;
+    sharedBufferB[p_idx] = p_color.b;
+}
+
+vec4 loadLDS(uint p_idx)
+{
+    return vec4(sharedBufferR[p_idx], sharedBufferG[p_idx], sharedBufferB[p_idx], 1.0);
+}
+
+layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE) in;
+
+void main()
+{
+	ivec2 texCoord = ivec2(gl_GlobalInvocationID);
+    ivec2 baseIndex = ivec2(gl_WorkGroupID) * GROUP_SIZE - FILTER_RADIUS;
+
+    // The first (TILE_PIXEL_COUNT - GROUP_THREAD_COUNT) threads load at most 2 texel values
+    for (int i = int(gl_LocalInvocationIndex); i < TILE_PIXEL_COUNT; i += GROUP_THREAD_COUNT)
+    {
+        vec2 uv        = (vec2(baseIndex) + 0.5) * texelSize;
+        vec2 uv_offset = vec2(i % TILE_SIZE, i / TILE_SIZE) * texelSize;
+        
+        vec4 color = textureLod(inputColorMap, uv + uv_offset, mipLevel);
+        storeLDS(i, color);
+    }
+
+    memoryBarrierShared();
+    barrier();
+
+    // Based on [Jimenez14] http://goo.gl/eomGso
+    // Define the center texel index
+    uint centerIndex = (gl_LocalInvocationID.x + FILTER_RADIUS) + (gl_LocalInvocationID.y + FILTER_RADIUS) * TILE_SIZE;
+
+	// Get the surrounding texels colors
+    vec4 A = loadLDS(centerIndex - TILE_SIZE - 1);
+    vec4 B = loadLDS(centerIndex - TILE_SIZE    );
+    vec4 C = loadLDS(centerIndex - TILE_SIZE + 1);
+    vec4 F = loadLDS(centerIndex - 1            );
+    vec4 G = loadLDS(centerIndex                );
+    vec4 H = loadLDS(centerIndex + 1            );
+    vec4 K = loadLDS(centerIndex + TILE_SIZE - 1);
+    vec4 L = loadLDS(centerIndex + TILE_SIZE    );
+    vec4 M = loadLDS(centerIndex + TILE_SIZE + 1);
+
+	// Combine the texel colors
+    vec4 D = (A + B + G + F) * 0.25;
+    vec4 E = (B + C + H + G) * 0.25;
+    vec4 I = (F + G + L + K) * 0.25;
+    vec4 J = (G + H + M + L) * 0.25;
+
+	// Calculate texel weights
+    vec2 div = (1.0 / 4.0) * vec2(0.5, 0.125);
+
+	// Sum and average out the colors based on the weights
+    vec4 c =  calculateKarisAverage((D + E + I + J) * div.x);
+         c += calculateKarisAverage((A + B + G + F) * div.y);
+         c += calculateKarisAverage((B + C + H + G) * div.y);
+         c += calculateKarisAverage((F + G + L + K) * div.y);
+         c += calculateKarisAverage((G + H + M + L) * div.y);
+
+	// Use threshold for the full sized image
+	if(mipLevel == 0)
+    {
+        c = calculateQuadraticThreshold(c, bloomTreshold.x, bloomTreshold.yzw);
+    }
+
+	imageStore(outputColorMap, texCoord, c);
+	//imageStore(outputColorMap, pixel_coords, textureLod(inputColorMap, pixel_coords, mipLevel));
+	//imageStore(outputColorMap, pixel_coords, vec4(0.0, 1.0, 0.0, 1.0));
+}

+ 90 - 0
Praxis3D/Data/Shaders/bloomUpscale.comp

@@ -0,0 +1,90 @@
+#version 460
+
+#define GROUP_SIZE         8
+#define GROUP_THREAD_COUNT (GROUP_SIZE * GROUP_SIZE)
+#define FILTER_SIZE        3
+#define FILTER_RADIUS      (FILTER_SIZE / 2)
+#define TILE_SIZE          (GROUP_SIZE + 2 * FILTER_RADIUS)
+#define TILE_PIXEL_COUNT   (TILE_SIZE * TILE_SIZE)
+
+layout(binding = 0)			 uniform sampler2D inputColorMap;
+layout(rgba16f, binding = 0) uniform image2D   outputColorMap;
+
+layout(binding = 1)			 uniform sampler2D lensDirtTexture;
+
+uniform int mipLevel;
+uniform vec2 texelSize;
+uniform float bloomIntensity;
+uniform float bloomDirtIntensity;
+
+// Local Data Storage buffers
+shared float sharedBufferR[TILE_PIXEL_COUNT];
+shared float sharedBufferG[TILE_PIXEL_COUNT];
+shared float sharedBufferB[TILE_PIXEL_COUNT];
+
+void storeLDS(int p_idx, vec4 p_color)
+{
+    sharedBufferR[p_idx] = p_color.r;
+    sharedBufferG[p_idx] = p_color.g;
+    sharedBufferB[p_idx] = p_color.b;
+}
+
+vec4 loadLDS(uint p_idx)
+{
+    return vec4(sharedBufferR[p_idx], sharedBufferG[p_idx], sharedBufferB[p_idx], 1.0);
+}
+
+layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE) in;
+
+void main()
+{
+	ivec2 texCoord = ivec2(gl_GlobalInvocationID.xy);
+    vec2  baseIndex = ivec2(gl_WorkGroupID) * GROUP_SIZE - FILTER_RADIUS;
+
+    // The first (TILE_PIXEL_COUNT - GROUP_THREAD_COUNT) threads load at most 2 texel values
+    for (int i = int(gl_LocalInvocationIndex); i < TILE_PIXEL_COUNT; i += GROUP_THREAD_COUNT)
+    {
+        vec2 uv        = (baseIndex + 0.5) * texelSize;
+        vec2 uv_offset = vec2(i % TILE_SIZE, i / TILE_SIZE) * texelSize;
+        
+        vec4 color = textureLod(inputColorMap, (uv + uv_offset), mipLevel);
+        storeLDS(i, color);
+    }
+
+    memoryBarrierShared();
+    barrier();
+
+    // Based on [Jimenez14] http://goo.gl/eomGso
+    // Define the center texel index
+    uint centerIndex = (gl_LocalInvocationID.x + FILTER_RADIUS) + (gl_LocalInvocationID.y + FILTER_RADIUS) * TILE_SIZE;
+
+	// Get the surrounding texels colors
+    vec4 s;
+    s =  loadLDS(centerIndex - TILE_SIZE - 1);
+    s += loadLDS(centerIndex - TILE_SIZE    ) * 2.0;
+    s += loadLDS(centerIndex - TILE_SIZE + 1);
+	
+    s += loadLDS(centerIndex - 1) * 2.0;
+    s += loadLDS(centerIndex    ) * 4.0;
+    s += loadLDS(centerIndex + 1) * 2.0;
+	
+    s += loadLDS(centerIndex + TILE_SIZE - 1);
+    s += loadLDS(centerIndex + TILE_SIZE    ) * 2.0;
+    s += loadLDS(centerIndex + TILE_SIZE + 1);
+
+	// Average out the bloom color
+    vec4 bloom = s * (1.0 / 16.0);
+
+	// Get the original pixel color and add bloom to it
+	vec4 finalColor = imageLoad(outputColorMap, texCoord);
+	finalColor += bloom * bloomIntensity;
+
+	// At the last upscaling run, apply the lens dirt texture
+    if (mipLevel == 1)
+    {
+        vec2  uv  = (vec2(texCoord) + vec2(0.5, 0.5)) * texelSize;
+        finalColor += texture(lensDirtTexture, uv) * bloomDirtIntensity * bloom * bloomIntensity;
+    }
+
+	imageStore(outputColorMap, texCoord, finalColor);
+}

+ 7 - 1
Praxis3D/Data/Shaders/finalPass.frag

@@ -65,11 +65,13 @@ vec2 calcTexCoord(void)
 
 
 void main(void)
 void main(void)
 {
 {
+	float exposure = 0.5;
+	
 	// Calculate screen-space texture coordinates, for buffer access
 	// Calculate screen-space texture coordinates, for buffer access
 	vec2 texCoord = calcTexCoord();
 	vec2 texCoord = calcTexCoord();
 	
 	
 	// Perform gamma correction on the color from the final framebuffer
 	// Perform gamma correction on the color from the final framebuffer
-	vec3 fragmentColor = texture(inputColorMap, texCoord).xyz;
+	vec3 fragmentColor = texture(inputColorMap, texCoord).xyz * exposure;
 	
 	
 	// Add emissive color (which is generated in a blur pass)
 	// Add emissive color (which is generated in a blur pass)
 	//fragmentColor += texture(emissiveMap, texCoord).xyz;
 	//fragmentColor += texture(emissiveMap, texCoord).xyz;
@@ -94,4 +96,8 @@ void main(void)
 	
 	
 	// Write the color to the framebuffer
 	// Write the color to the framebuffer
 	outputColor = vec4(fragmentColor, 1.0);
 	outputColor = vec4(fragmentColor, 1.0);
+	//outputColor = vec4(texture(inputColorMap, texCoord).xyz, 1.0);
+	//outputColor = vec4(1.0, 0.0, 1.0, 1.0);
+	//outputColor = vec4(texture(emissiveMap, texCoord).xyz, 1.0);
+	
 }
 }

+ 2 - 2
Praxis3D/Data/Shaders/hdrMappingPass.frag

@@ -58,8 +58,8 @@ void main(void)
 	vec3 fragmentColor = texture(inputColorMap, texCoord).xyz;
 	vec3 fragmentColor = texture(inputColorMap, texCoord).xyz;
 	
 	
 	// Adjust the fragment brightness based on average
 	// Adjust the fragment brightness based on average
-	fragmentColor = brightnessMapping(fragmentColor, avgBrightness);
-	emissiveColor = brightnessMapping(emissiveColor, avgBrightness);
+	//fragmentColor = brightnessMapping(fragmentColor, avgBrightness);
+	//emissiveColor = brightnessMapping(emissiveColor, avgBrightness);
 	
 	
 	// Calculate luminance of the fragment after HDR mapping
 	// Calculate luminance of the fragment after HDR mapping
 	float luminance = max(0.0, calcLuma(fragmentColor) - 1.0);
 	float luminance = max(0.0, calcLuma(fragmentColor) - 1.0);

+ 1 - 0
Praxis3D/Data/Shaders/lightPass.frag

@@ -284,5 +284,6 @@ void main(void)
 	}
 	}
 	
 	
 	colorBuffer = vec4(finalLightColor + emissiveColor, 1.0);
 	colorBuffer = vec4(finalLightColor + emissiveColor, 1.0);
+	//colorBuffer = vec4(0.0, 1.0, 0.0, 1.0);
 	//colorBuffer = vec4(diffuseColor + emissiveColor, 1.0);
 	//colorBuffer = vec4(diffuseColor + emissiveColor, 1.0);
 }
 }

+ 3 - 3
Praxis3D/Data/config.ini

@@ -6,15 +6,15 @@ window_size_fullscreen_x 1920
 window_size_fullscreen_y 1080
 window_size_fullscreen_y 1080
 fullscreen 0
 fullscreen 0
 fullscreen_borderless 1
 fullscreen_borderless 1
-gl_context_major_version 3
-gl_context_minor_version 3
+gl_context_major_version 4
+gl_context_minor_version 6
 vertical_sync 1
 vertical_sync 1
 default_texture default.png
 default_texture default.png
 generate_mipmaps 1
 generate_mipmaps 1
 gl_texture_anisotropy 16
 gl_texture_anisotropy 16
 camera_freelook_speed 25
 camera_freelook_speed 25
 face_culling 0
 face_culling 0
-eye_adaption 1
+eye_adaption 0
 eye_adaption_intended_brightness 0.5
 eye_adaption_intended_brightness 0.5
 mouse_captured 1
 mouse_captured 1
 mouse_warp_mode 0
 mouse_warp_mode 0

+ 2 - 1
Praxis3D/Praxis3D.vcxproj

@@ -115,7 +115,7 @@
       <WarningLevel>Level3</WarningLevel>
       <WarningLevel>Level3</WarningLevel>
       <SDLCheck>true</SDLCheck>
       <SDLCheck>true</SDLCheck>
       <Optimization>Disabled</Optimization>
       <Optimization>Disabled</Optimization>
-      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>NOMINMAX;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
       <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
       <ConformanceMode>false</ConformanceMode>
       <ConformanceMode>false</ConformanceMode>
@@ -216,6 +216,7 @@
     <ClInclude Include="Source\BaseGraphicsObjects.h" />
     <ClInclude Include="Source\BaseGraphicsObjects.h" />
     <ClInclude Include="Source\BaseScriptObject.h" />
     <ClInclude Include="Source\BaseScriptObject.h" />
     <ClInclude Include="Source\BloomCompositePass.h" />
     <ClInclude Include="Source\BloomCompositePass.h" />
+    <ClInclude Include="Source\BloomPass.h" />
     <ClInclude Include="Source\BlurPass.h" />
     <ClInclude Include="Source\BlurPass.h" />
     <ClInclude Include="Source\CameraComponent.h" />
     <ClInclude Include="Source\CameraComponent.h" />
     <ClInclude Include="Source\CameraGraphicsObject.h" />
     <ClInclude Include="Source\CameraGraphicsObject.h" />

+ 3 - 0
Praxis3D/Praxis3D.vcxproj.filters

@@ -803,6 +803,9 @@
     <ClInclude Include="Source\EntityViewDefinitions.h">
     <ClInclude Include="Source\EntityViewDefinitions.h">
       <Filter>Header Files</Filter>
       <Filter>Header Files</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Source\BloomPass.h">
+      <Filter>Renderer\Render Passes\Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <None Include="Data\config.ini" />
     <None Include="Data\config.ini" />

+ 157 - 0
Praxis3D/Source/BloomPass.h

@@ -0,0 +1,157 @@
+#pragma once
+
+#include "GraphicsDataSets.h"
+#include "RenderPassBase.h"
+
+class BloomPass : public RenderPass
+{
+public:
+	BloomPass(RendererFrontend &p_renderer) :
+		RenderPass(p_renderer),
+		m_lensDirtTexture(Loaders::texture2D().load(Config::rendererVar().lens_flare_dirt_texture)),
+		m_bloomDownscaleShader(nullptr),
+		m_bloomUpscaleShader(nullptr) { }
+
+	~BloomPass() { }
+
+	ErrorCode init()
+	{
+		ErrorCode returnError = ErrorCode::Failure;
+
+		m_name = "Bloom Pass";
+		
+		// Create a property-set used to load bloom downscale compute shader
+		PropertySet bloomDownscaleProperty(Properties::Shaders);
+		bloomDownscaleProperty.addProperty(Properties::ComputeShader, Config::rendererVar().bloom_downscale_comp_shader);
+
+		// Create a property-set used to load bloom upscale compute shader
+		PropertySet bloomUpscaleProperty(Properties::Shaders);
+		bloomUpscaleProperty.addProperty(Properties::ComputeShader, Config::rendererVar().bloom_upscale_comp_shader);
+
+		// Create shaders
+		m_bloomDownscaleShader = Loaders::shader().load(bloomDownscaleProperty);
+		m_bloomUpscaleShader = Loaders::shader().load(bloomUpscaleProperty);
+
+		// Load shaders to memory
+		ErrorCode downscaleError = m_bloomDownscaleShader->loadToMemory();
+		ErrorCode upscaleError = m_bloomUpscaleShader->loadToMemory();
+
+		// Queue the shaders to be loaded to GPU
+		if(downscaleError == ErrorCode::Success)
+			m_renderer.queueForLoading(*m_bloomDownscaleShader);
+		if(upscaleError == ErrorCode::Success)
+			m_renderer.queueForLoading(*m_bloomUpscaleShader);
+
+		// Check for errors and log either a successful or a failed initialization
+		if(downscaleError == ErrorCode::Success && upscaleError == ErrorCode::Success)
+		{
+			ErrHandlerLoc::get().log(ErrorCode::Initialize_success, ErrorSource::Source_BloomPass);
+			returnError = ErrorCode::Success;
+		}
+		else
+		{
+			ErrHandlerLoc::get().log(ErrorCode::Initialize_failure, ErrorSource::Source_BloomPass);
+
+			// Assign the error code of the failed shader
+			if(downscaleError != ErrorCode::Success)
+				returnError = downscaleError;
+			else
+				returnError = upscaleError;
+		}
+
+		m_bloomTreshold = glm::vec4(Config::graphicsVar().bloom_threshold, Config::graphicsVar().bloom_threshold - Config::graphicsVar().bloom_knee, 2.0f * Config::graphicsVar().bloom_knee, 0.25f * Config::graphicsVar().bloom_knee);
+
+		// Load lens dirt texture to memory and to video memory
+		m_lensDirtTexture.loadToMemory();
+		m_renderer.queueForLoading(m_lensDirtTexture);
+
+		return returnError;
+	}
+
+	// Calculates the maximum mipmap levels based on the image size and bloom mipmap, bloom downscale limits 
+	unsigned int calculateMipmapLevels(unsigned int p_width, unsigned int p_height)
+	{
+		unsigned int width = p_width / 2;
+		unsigned int height = p_height / 2;
+		unsigned int mipLevels = 1;
+
+		for(unsigned int i = 0; i < Config::graphicsVar().bloom_mipmap_limit; i++)
+		{
+			width = width / 2;
+			height = height / 2;
+
+			if(width < Config::graphicsVar().bloom_downscale_limit || height < Config::graphicsVar().bloom_downscale_limit) break;
+
+			mipLevels++;
+		}
+
+		return mipLevels + 1;
+	}
+
+	void update(RenderPassData &p_renderPassData, const SceneObjects &p_sceneObjects, const float p_deltaTime)
+	{
+		// Assign the bloom threshold value so it can be sent to the shader
+		m_renderer.m_frameData.m_bloomTreshold = m_bloomTreshold;
+
+		// Get the screen image buffer size
+		const unsigned int imageWidth = m_renderer.m_backend.getGeometryBuffer()->getBufferWidth();
+		const unsigned int imageHeight = m_renderer.m_backend.getGeometryBuffer()->getBufferHeight();
+
+		// Calculate mipmap size and level
+		glm::uvec2 mipmapSize = glm::uvec2(imageWidth / 2, imageHeight / 2);
+		unsigned int mipmapLevels = calculateMipmapLevels(imageWidth, imageHeight);
+
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferFinal, GeometryBuffer::GBufferInputTexture);
+
+		// Bloom downscaling
+		for(unsigned int i = 0; i < mipmapLevels - 1; i++)
+		{
+			// Assign the texel size and mipmap level so it can be sent to the shader
+			m_renderer.m_frameData.m_texelSize = 1.0f / glm::vec2(mipmapSize);
+			m_renderer.m_frameData.m_mipLevel = i;
+
+			// Bind the corresponding mipmap level of the image buffer
+			m_renderer.m_backend.getGeometryBuffer()->bindBufferToImageUnitForWriting(GeometryBuffer::GBufferFinal, 0, i + 1);
+
+			// Dispatch the compute shader
+			m_renderer.queueForDrawing(m_bloomDownscaleShader->getShaderHandle(), m_bloomDownscaleShader->getUniformUpdater(), p_sceneObjects.m_camera.m_spatialData.m_transformMat, glm::ceil(float(mipmapSize.x) / 8), glm::ceil(float(mipmapSize.y) / 8), 1, MemoryBarrierType::MemoryBarrierType_AccessAndFetchBarrier);
+			m_renderer.passComputeDispatchCommandsToBackend();
+			
+			// Half the mipmap size as we go up the mipmap levels
+			mipmapSize = mipmapSize / 2u;
+		}
+
+		// Bind lens dirt texture
+		glActiveTexture(GL_TEXTURE0 + LensFlareTextureType::LensFlareTextureType_LenseDirt);
+		glBindTexture(GL_TEXTURE_2D, m_lensDirtTexture.getHandle());
+
+		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferFinal, GeometryBuffer::GBufferInputTexture);
+
+		// Bloom upscaling
+		for(unsigned int i = mipmapLevels - 1; i >= 1; i--)
+		{
+			// Recalculate the mipmap size as we go down the mipmap levels
+			mipmapSize.x = glm::max(1.0, glm::floor(float(imageWidth) / glm::pow(2.0, i - 1)));
+			mipmapSize.y = glm::max(1.0, glm::floor(float(imageHeight) / glm::pow(2.0, i - 1)));
+
+			// Assign the texel size and mipmap level so it can be sent to the shader
+			m_renderer.m_frameData.m_texelSize = 1.0f / glm::vec2(mipmapSize);
+			m_renderer.m_frameData.m_mipLevel = i;
+
+			// Bind the corresponding mipmap level of the image buffer
+			m_renderer.m_backend.getGeometryBuffer()->bindBufferToImageUnitForWriting(GeometryBuffer::GBufferFinal, 0, i - 1);
+
+			// Dispatch the compute shader
+			m_renderer.queueForDrawing(m_bloomUpscaleShader->getShaderHandle(), m_bloomUpscaleShader->getUniformUpdater(), p_sceneObjects.m_camera.m_spatialData.m_transformMat, glm::ceil(float(mipmapSize.x) / 8), glm::ceil(float(mipmapSize.y) / 8), 1, MemoryBarrierType::MemoryBarrierType_AccessAndFetchBarrier);
+			m_renderer.passComputeDispatchCommandsToBackend();
+		}
+	}
+
+private:
+	ShaderLoader::ShaderProgram *m_bloomDownscaleShader;
+	ShaderLoader::ShaderProgram *m_bloomUpscaleShader;
+
+	TextureLoader2D::Texture2DHandle m_lensDirtTexture;
+
+	glm::vec4 m_bloomTreshold;
+};

+ 9 - 0
Praxis3D/Source/CommonDefinitions.h

@@ -18,9 +18,16 @@ enum CommandType : unsigned int
 {
 {
 	CommandType_Draw,
 	CommandType_Draw,
 	CommandType_ScreenSpaceDraw,
 	CommandType_ScreenSpaceDraw,
+	CommandType_Compute,
 	CommandType_Bind,
 	CommandType_Bind,
 	CommandType_Load
 	CommandType_Load
 };
 };
+enum MemoryBarrierType : unsigned int
+{
+	MemoryBarrierType_All,
+	MemoryBarrierType_ImageAccessBarrier,
+	MemoryBarrierType_AccessAndFetchBarrier
+};
 enum RenderPassType : unsigned int
 enum RenderPassType : unsigned int
 {
 {
 	RenderPassType_Geometry,
 	RenderPassType_Geometry,
@@ -28,6 +35,7 @@ enum RenderPassType : unsigned int
 	RenderPassType_AtmScattering,
 	RenderPassType_AtmScattering,
 	RenderPassType_HdrMapping,
 	RenderPassType_HdrMapping,
 	RenderPassType_Blur,
 	RenderPassType_Blur,
+	RenderPassType_Bloom,
 	RenderPassType_BloomComposite,
 	RenderPassType_BloomComposite,
 	RenderPassType_LenseFlare,
 	RenderPassType_LenseFlare,
 	RenderPassType_LenseFlareComposite,
 	RenderPassType_LenseFlareComposite,
@@ -121,6 +129,7 @@ enum ShaderType : unsigned int
 {
 {
 	// WARNING: do not change the order - enum entries are order-sensitive
 	// WARNING: do not change the order - enum entries are order-sensitive
 
 
+	ShaderType_Compute,
 	ShaderType_Fragment,
 	ShaderType_Fragment,
 	ShaderType_Geometry,
 	ShaderType_Geometry,
 	ShaderType_Vertex,
 	ShaderType_Vertex,

+ 37 - 5
Praxis3D/Source/Config.h

@@ -229,6 +229,7 @@ namespace Properties
 	Code(CameraComponent,) \
 	Code(CameraComponent,) \
 	Code(Color,) \
 	Code(Color,) \
 	Code(CombinedTexture,) \
 	Code(CombinedTexture,) \
+	Code(ComputeShader,) \
 	Code(CutoffAngle,) \
 	Code(CutoffAngle,) \
 	Code(Diffuse,) \
 	Code(Diffuse,) \
 	Code(Direction,) \
 	Code(Direction,) \
@@ -411,6 +412,7 @@ namespace Properties
 		GetString(CameraComponent),
 		GetString(CameraComponent),
 		GetString(Color),
 		GetString(Color),
 		GetString(CombinedTexture),
 		GetString(CombinedTexture),
+		GetString(ComputeShader),
 		GetString(CutoffAngle),
 		GetString(CutoffAngle),
 		GetString(Diffuse),
 		GetString(Diffuse),
 		GetString(Direction),
 		GetString(Direction),
@@ -694,8 +696,8 @@ public:
 			gl_blur_buffer_texture_format = GL_RGBA;
 			gl_blur_buffer_texture_format = GL_RGBA;
 			gl_blur_buffer_texture_type = GL_FLOAT;
 			gl_blur_buffer_texture_type = GL_FLOAT;
 
 
-			gl_final_buffer_internal_format = GL_RGB16F;
-			gl_final_buffer_texture_format = GL_RGB;
+			gl_final_buffer_internal_format = GL_RGBA16F;
+			gl_final_buffer_texture_format = GL_RGBA;
 			gl_final_buffer_texture_type = GL_FLOAT;
 			gl_final_buffer_texture_type = GL_FLOAT;
 
 
 			gl_depth_buffer_internal_format = GL_DEPTH_COMPONENT32F;
 			gl_depth_buffer_internal_format = GL_DEPTH_COMPONENT32F;
@@ -712,7 +714,7 @@ public:
 			gl_blur_buffer_wrap_s_method = GL_CLAMP_TO_EDGE;
 			gl_blur_buffer_wrap_s_method = GL_CLAMP_TO_EDGE;
 			gl_blur_buffer_wrap_t_method = GL_CLAMP_TO_EDGE;
 			gl_blur_buffer_wrap_t_method = GL_CLAMP_TO_EDGE;
 
 
-			gl_final_buffer_min_filter_HDR = GL_NEAREST_MIPMAP_NEAREST;
+			gl_final_buffer_min_filter_HDR = GL_LINEAR_MIPMAP_NEAREST;
 			gl_final_buffer_min_filter = GL_NEAREST;
 			gl_final_buffer_min_filter = GL_NEAREST;
 			gl_final_buffer_mag_filter = GL_NEAREST;
 			gl_final_buffer_mag_filter = GL_NEAREST;
 			gl_final_buffer_s_method = GL_CLAMP_TO_EDGE;
 			gl_final_buffer_s_method = GL_CLAMP_TO_EDGE;
@@ -782,11 +784,14 @@ public:
 	{
 	{
 		GraphicsVariables()
 		GraphicsVariables()
 		{
 		{
+			bloom_enabled = true;
 			double_buffering = true;
 			double_buffering = true;
-			eye_adaption = true;
+			eye_adaption = false;
 			multisampling = true;
 			multisampling = true;
 			alpha_size = 8;
 			alpha_size = 8;
 			bloom_blur_passes = 5;
 			bloom_blur_passes = 5;
+			bloom_downscale_limit = 10;
+			bloom_mipmap_limit = 16;
 			current_resolution_x = 0;
 			current_resolution_x = 0;
 			current_resolution_y = 0;
 			current_resolution_y = 0;
 			dir_shadow_res_x = 2048;
 			dir_shadow_res_x = 2048;
@@ -800,6 +805,10 @@ public:
 			rendering_res_x = 1600;
 			rendering_res_x = 1600;
 			rendering_res_y = 900;
 			rendering_res_y = 900;
 			alpha_threshold = 0.0f;
 			alpha_threshold = 0.0f;
+			bloom_intensity = 1.0f;
+			bloom_knee = 0.1f;
+			bloom_threshold = 1.5f;
+			bloom_dirt_intensity = 1.0f;
 			emissive_multiplier = 10.0f;
 			emissive_multiplier = 10.0f;
 			emissive_threshold = 0.01f;
 			emissive_threshold = 0.01f;
 			eye_adaption_rate = 0.25f;
 			eye_adaption_rate = 0.25f;
@@ -831,11 +840,14 @@ public:
 			z_near = 0.1f;
 			z_near = 0.1f;
 		}
 		}
 
 
+		bool bloom_enabled;
 		bool double_buffering;
 		bool double_buffering;
 		bool eye_adaption;
 		bool eye_adaption;
 		bool multisampling;
 		bool multisampling;
 		int alpha_size;
 		int alpha_size;
 		int bloom_blur_passes;
 		int bloom_blur_passes;
+		int bloom_downscale_limit;
+		int bloom_mipmap_limit;
 		int current_resolution_x;
 		int current_resolution_x;
 		int current_resolution_y;
 		int current_resolution_y;
 		int dir_shadow_res_x;
 		int dir_shadow_res_x;
@@ -849,6 +861,10 @@ public:
 		int rendering_res_x;
 		int rendering_res_x;
 		int rendering_res_y;
 		int rendering_res_y;
 		float alpha_threshold;
 		float alpha_threshold;
+		float bloom_intensity;
+		float bloom_knee;
+		float bloom_threshold;
+		float bloom_dirt_intensity;
 		float emissive_multiplier;
 		float emissive_multiplier;
 		float emissive_threshold;
 		float emissive_threshold;
 		float eye_adaption_rate;
 		float eye_adaption_rate;
@@ -1065,6 +1081,8 @@ public:
 			hdr_mapping_pass_vert_shader = "hdrMappingPass.vert";
 			hdr_mapping_pass_vert_shader = "hdrMappingPass.vert";
 			bloom_composite_pass_vert_shader = "bloomCompositePass.vert";
 			bloom_composite_pass_vert_shader = "bloomCompositePass.vert";
 			bloom_composite_pass_frag_shader = "bloomCompositePass.frag";
 			bloom_composite_pass_frag_shader = "bloomCompositePass.frag";
+			bloom_downscale_comp_shader = "bloomDownscale.comp";
+			bloom_upscale_comp_shader = "bloomUpscale.comp";
 			blur_pass_vert_shader = "blurPass.vert";
 			blur_pass_vert_shader = "blurPass.vert";
 			blur_pass_frag_shader = "blurPass.frag";
 			blur_pass_frag_shader = "blurPass.frag";
 			lense_flare_comp_pass_vert_shader = "lenseFlareCompositePass.vert";
 			lense_flare_comp_pass_vert_shader = "lenseFlareCompositePass.vert";
@@ -1079,7 +1097,7 @@ public:
 			postProcess_pass_frag_shader = "postProcessPass.frag";
 			postProcess_pass_frag_shader = "postProcessPass.frag";
 			reflection_pass_vert_shader = "reflectionPass.vert";
 			reflection_pass_vert_shader = "reflectionPass.vert";
 			reflection_pass_frag_shader = "reflectionPass.frag";
 			reflection_pass_frag_shader = "reflectionPass.frag";
-			lens_flare_dirt_texture = "p3d_lensFlareDirt.png";
+			lens_flare_dirt_texture = "DirtMaskTexture.png";
 			lens_flare_ghost_gradient_texture = "p3d_lensFlareGhostColorGradient.png";
 			lens_flare_ghost_gradient_texture = "p3d_lensFlareGhostColorGradient.png";
 			lens_flare_starburst_texture = "p3d_lensFlareStarburst.png";
 			lens_flare_starburst_texture = "p3d_lensFlareStarburst.png";
 			dir_light_quad_offset_x = 0.0f;
 			dir_light_quad_offset_x = 0.0f;
@@ -1128,6 +1146,8 @@ public:
 		std::string hdr_mapping_pass_vert_shader;
 		std::string hdr_mapping_pass_vert_shader;
 		std::string bloom_composite_pass_vert_shader;
 		std::string bloom_composite_pass_vert_shader;
 		std::string bloom_composite_pass_frag_shader;
 		std::string bloom_composite_pass_frag_shader;
+		std::string bloom_downscale_comp_shader;
+		std::string bloom_upscale_comp_shader;
 		std::string blur_pass_vert_shader;
 		std::string blur_pass_vert_shader;
 		std::string blur_pass_frag_shader;
 		std::string blur_pass_frag_shader;
 		std::string lense_flare_comp_pass_vert_shader;
 		std::string lense_flare_comp_pass_vert_shader;
@@ -1201,6 +1221,8 @@ public:
 			heightScaleUniform = "heightScale";
 			heightScaleUniform = "heightScale";
 			textureTilingFactorUniform = "textureTilingFactor";
 			textureTilingFactorUniform = "textureTilingFactor";
 			LODParallaxUniform = "parallaxMappingLOD";
 			LODParallaxUniform = "parallaxMappingLOD";
+			texelSize = "texelSize";
+			mipLevel = "mipLevel";
 
 
 			dirLightColor = "directionalLight.m_color";
 			dirLightColor = "directionalLight.m_color";
 			dirLightDirection = "directionalLight.m_direction";
 			dirLightDirection = "directionalLight.m_direction";
@@ -1247,6 +1269,10 @@ public:
 			atmSingleMieScatTextureUniform = "atmSingleMieTexture";
 			atmSingleMieScatTextureUniform = "atmSingleMieTexture";
 			atmTransmittanceTextureUniform = "atmTransmitTexture";
 			atmTransmittanceTextureUniform = "atmTransmitTexture";
 
 
+			bloomTreshold = "bloomTreshold";
+			bloomIntensity = "bloomIntensity";
+			bloomDirtIntensity = "bloomDirtIntensity";
+
 			lensFlareDirtTextureUniform = "lensDirtTexture";
 			lensFlareDirtTextureUniform = "lensDirtTexture";
 			lensFlareGhostGradientTextureUniform = "ghostGradientTexture";
 			lensFlareGhostGradientTextureUniform = "ghostGradientTexture";
 			lensFlareStarburstTextureUniform = "lenseStarburstTexture";
 			lensFlareStarburstTextureUniform = "lenseStarburstTexture";
@@ -1290,6 +1316,8 @@ public:
 		std::string heightScaleUniform;
 		std::string heightScaleUniform;
 		std::string textureTilingFactorUniform;
 		std::string textureTilingFactorUniform;
 		std::string LODParallaxUniform;
 		std::string LODParallaxUniform;
+		std::string texelSize;
+		std::string mipLevel;
 
 
 		std::string dirLightColor;
 		std::string dirLightColor;
 		std::string dirLightDirection;
 		std::string dirLightDirection;
@@ -1336,6 +1364,10 @@ public:
 		std::string atmSingleMieScatTextureUniform;
 		std::string atmSingleMieScatTextureUniform;
 		std::string atmTransmittanceTextureUniform;
 		std::string atmTransmittanceTextureUniform;
 		
 		
+		std::string bloomTreshold;
+		std::string bloomIntensity;
+		std::string bloomDirtIntensity;
+
 		std::string lensFlareDirtTextureUniform;
 		std::string lensFlareDirtTextureUniform;
 		std::string lensFlareGhostGradientTextureUniform;
 		std::string lensFlareGhostGradientTextureUniform;
 		std::string lensFlareStarburstTextureUniform;
 		std::string lensFlareStarburstTextureUniform;

+ 7 - 6
Praxis3D/Source/FinalPass.h

@@ -13,10 +13,10 @@ public:
 
 
 	ErrorCode init()
 	ErrorCode init()
 	{
 	{
-		ErrorCode returnError;
+		ErrorCode returnError = ErrorCode::Failure;
+
+		m_name = "Final Pass";
 
 
-		m_name = "Final Rendering Pass";
-		
 		// Create a property-set used to load geometry shader
 		// Create a property-set used to load geometry shader
 		PropertySet finalShaderProperties(Properties::Shaders);
 		PropertySet finalShaderProperties(Properties::Shaders);
 		finalShaderProperties.addProperty(Properties::VertexShader, Config::rendererVar().final_pass_vert_shader);
 		finalShaderProperties.addProperty(Properties::VertexShader, Config::rendererVar().final_pass_vert_shader);
@@ -57,13 +57,13 @@ public:
 		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferFinal, GeometryBuffer::GBufferFinal);
 		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferFinal, GeometryBuffer::GBufferFinal);
 
 
 #else
 #else
-
 		// Bind final framebuffer
 		// Bind final framebuffer
 		//m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferFinal, GeometryBuffer::GBufferFinal);
 		//m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferFinal, GeometryBuffer::GBufferFinal);
 
 
+		glDepthFunc(GL_LEQUAL);
 		glDisable(GL_DEPTH_TEST);
 		glDisable(GL_DEPTH_TEST);
 		
 		
-		if(Config::graphicsVar().eye_adaption)
+		if(Config::graphicsVar().bloom_enabled)
 		{
 		{
 			// Generate mipmaps for the final buffer, for use in tone mapping
 			// Generate mipmaps for the final buffer, for use in tone mapping
 			//m_renderer.m_backend.getGeometryBuffer()->generateMipmap(GeometryBuffer::GBufferFinal);
 			//m_renderer.m_backend.getGeometryBuffer()->generateMipmap(GeometryBuffer::GBufferFinal);
@@ -72,6 +72,7 @@ public:
 		// Bind final texture for reading so it can be accessed in the shaders
 		// Bind final texture for reading so it can be accessed in the shaders
 		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferEmissive, GeometryBuffer::GBufferEmissive);
 		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferEmissive, GeometryBuffer::GBufferEmissive);
 		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(p_renderPassData.getColorInputMap(), GeometryBuffer::GBufferInputTexture);
 		m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(p_renderPassData.getColorInputMap(), GeometryBuffer::GBufferInputTexture);
+		//m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferFinal, GeometryBuffer::GBufferInputTexture);
 		//m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferNormal, GeometryBuffer::GBufferInputTexture);
 		//m_renderer.m_backend.getGeometryBuffer()->bindBufferForReading(GeometryBuffer::GBufferNormal, GeometryBuffer::GBufferInputTexture);
 
 
 		// Set the default framebuffer to be drawn to
 		// Set the default framebuffer to be drawn to
@@ -85,5 +86,5 @@ public:
 	}
 	}
 
 
 private:
 private:
-	ShaderLoader::ShaderProgram	*m_shaderFinalPass;
+	ShaderLoader::ShaderProgram *m_shaderFinalPass;
 };
 };

+ 4 - 0
Praxis3D/Source/Framebuffer.h

@@ -39,6 +39,10 @@ public:
 	GLuint getStatus() { return m_status; }
 	GLuint getStatus() { return m_status; }
 
 
 	virtual ErrorCode init() = 0;
 	virtual ErrorCode init() = 0;
+	
+	inline unsigned int getBufferWidth() const { return m_bufferWidth; }
+	inline unsigned int getBufferHeight() const { return m_bufferHeight; }
+	
 	// Set the size of all buffers
 	// Set the size of all buffers
 	virtual void setBufferSize(unsigned int p_bufferWidth, unsigned int p_bufferHeight) = 0;
 	virtual void setBufferSize(unsigned int p_bufferWidth, unsigned int p_bufferHeight) = 0;
 	// Set the size of an individual buffer
 	// Set the size of an individual buffer

+ 0 - 18
Praxis3D/Source/GUIHandler.cpp

@@ -3,24 +3,6 @@
 
 
 void GUIHandler::render()
 void GUIHandler::render()
 {
 {
-	//ImGui::ShowDemoWindow(&m_showDemoWindow);
-	
-	//ImGui::SetNextWindowSize(ImVec2(600.0f, 900.0f));
-	// Create a window called "My First Tool", with a menu bar.
-	//ImGui::Begin("My First Tool", &m_window1Open, ImGuiWindowFlags_MenuBar);
-
-	//ImGui::Text("Hello, world %d", 123);
-
-	//ImGui::End();
-
-	//ImGui::Begin("My First Tool");
-	//ImGui::Text("Hello, world");
-	//ImGui::End();
-
-	//glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
-	//glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
-	//glClear(GL_COLOR_BUFFER_BIT);
-
 	// Create draw data from GUI elements
 	// Create draw data from GUI elements
 	ImGui::Render();
 	ImGui::Render();
 
 

+ 7 - 4
Praxis3D/Source/GeometryBuffer.cpp

@@ -107,12 +107,12 @@ ErrorCode GeometryBuffer::init()
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, Config::FramebfrVariables().gl_buffers_wrap_t_method);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, Config::FramebfrVariables().gl_buffers_wrap_t_method);
 		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBufferIntermediate, GL_TEXTURE_2D, m_intermediateBuffer, 0);
 		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBufferIntermediate, GL_TEXTURE_2D, m_intermediateBuffer, 0);
 
 
-		// Create the final buffer, that gets renderred to the screen
+		// Create the final buffer, that gets rendered to the screen
 		glBindTexture(GL_TEXTURE_2D, m_finalBuffer);
 		glBindTexture(GL_TEXTURE_2D, m_finalBuffer);
 		glTexImage2D(GL_TEXTURE_2D, 0, Config::FramebfrVariables().gl_final_buffer_internal_format, m_bufferWidth, m_bufferHeight, 0, 
 		glTexImage2D(GL_TEXTURE_2D, 0, Config::FramebfrVariables().gl_final_buffer_internal_format, m_bufferWidth, m_bufferHeight, 0, 
 					 Config::FramebfrVariables().gl_final_buffer_texture_format, Config::FramebfrVariables().gl_final_buffer_texture_type, NULL);
 					 Config::FramebfrVariables().gl_final_buffer_texture_format, Config::FramebfrVariables().gl_final_buffer_texture_type, NULL);
-		// If eye adaption (HDR) is enabled, buffer should use a different min_filter (to support mipmapping)
-		if(Config::graphicsVar().eye_adaption)
+		// If HDR bloom is enabled, buffer should use a different min_filter (to support mipmapping)
+		if(Config::graphicsVar().bloom_enabled)
 			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Config::FramebfrVariables().gl_final_buffer_min_filter_HDR);
 			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Config::FramebfrVariables().gl_final_buffer_min_filter_HDR);
 		else
 		else
 			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Config::FramebfrVariables().gl_final_buffer_min_filter);
 			glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, Config::FramebfrVariables().gl_final_buffer_min_filter);
@@ -120,7 +120,10 @@ ErrorCode GeometryBuffer::init()
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, Config::FramebfrVariables().gl_buffers_wrap_s_method);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, Config::FramebfrVariables().gl_buffers_wrap_s_method);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, Config::FramebfrVariables().gl_buffers_wrap_t_method);
 		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, Config::FramebfrVariables().gl_buffers_wrap_t_method);
 		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBufferFinal, GL_TEXTURE_2D, m_finalBuffer, 0);
 		glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + GBufferFinal, GL_TEXTURE_2D, m_finalBuffer, 0);
-		
+		// If HDR bloom is enabled, create mip maps for the final buffer
+		if(Config::graphicsVar().bloom_enabled)
+			generateMipmap(GeometryBuffer::GBufferFinal);
+
 		// Check for errors and return an error in case of one
 		// Check for errors and return an error in case of one
 		m_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 		m_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 		if(m_status != GL_FRAMEBUFFER_COMPLETE)
 		if(m_status != GL_FRAMEBUFFER_COMPLETE)

+ 42 - 3
Praxis3D/Source/GeometryBuffer.h

@@ -5,6 +5,7 @@
 
 
 class GeometryBuffer : public Framebuffer
 class GeometryBuffer : public Framebuffer
 {
 {
+	friend class BloomPass;
 public:
 public:
 	enum GBufferFramebufferType : unsigned int
 	enum GBufferFramebufferType : unsigned int
 	{
 	{
@@ -19,8 +20,8 @@ public:
 		GBufferNormal,
 		GBufferNormal,
 		GBufferEmissive,
 		GBufferEmissive,
 		GBufferMatProperties,
 		GBufferMatProperties,
-		GBufferNumTextures,
-		GBufferFinal = GBufferNumTextures,
+		GBufferFinal,
+		GBufferNumTextures = GBufferFinal,
 		GBufferIntermediate,
 		GBufferIntermediate,
 		GBufferTotalNumTextures,
 		GBufferTotalNumTextures,
 		GBufferInputTexture = GBufferTotalNumTextures,
 		GBufferInputTexture = GBufferTotalNumTextures,
@@ -98,7 +99,20 @@ public:
 	{
 	{
 		glDrawBuffers((GLsizei)p_buffers.size(), p_buffers.data());
 		glDrawBuffers((GLsizei)p_buffers.size(), p_buffers.data());
 	}
 	}
-	
+
+	inline void bindBufferToImageUnitForReading(const GBufferTextureType p_buffer, const int p_imageUnitIndex = 0, const int p_mipLevel = 0)
+	{
+		bindBufferToImageUnit(p_buffer, p_imageUnitIndex, p_mipLevel, GL_READ_ONLY);
+	}
+	inline void bindBufferToImageUnitForWriting(const GBufferTextureType p_buffer, const int p_imageUnitIndex = 0, const int p_mipLevel = 0)
+	{
+		bindBufferToImageUnit(p_buffer, p_imageUnitIndex, p_mipLevel, GL_WRITE_ONLY);
+	}
+	inline void bindBufferToImageUnitForReadWrite(const GBufferTextureType p_buffer, const int p_imageUnitIndex = 0, const int p_mipLevel = 0)
+	{
+		bindBufferToImageUnit(p_buffer, p_imageUnitIndex, p_mipLevel, GL_READ_WRITE);
+	}
+
 	// Framebuffer binding functions
 	// Framebuffer binding functions
 	inline void bindFramebufferForReading(GBufferFramebufferType p_framebufferType)
 	inline void bindFramebufferForReading(GBufferFramebufferType p_framebufferType)
 	{
 	{
@@ -144,6 +158,31 @@ public:
 	}
 	}
 
 
 protected:
 protected:
+	inline void bindBufferToImageUnit(const GBufferTextureType p_buffer, const int p_imageUnitIndex, const int p_mipLevel, const GLenum p_access)
+	{
+		switch(p_buffer)
+		{
+		case GeometryBuffer::GBufferPosition:
+			glBindImageTexture(p_imageUnitIndex, m_GBTextures[p_buffer], p_mipLevel, GL_FALSE, 0, p_access, Config::FramebfrVariables().gl_position_buffer_internal_format);
+		case GeometryBuffer::GBufferDiffuse:
+			glBindImageTexture(p_imageUnitIndex, m_GBTextures[p_buffer], p_mipLevel, GL_FALSE, 0, p_access, Config::FramebfrVariables().gl_diffuse_buffer_internal_format);
+		case GeometryBuffer::GBufferNormal:
+			glBindImageTexture(p_imageUnitIndex, m_GBTextures[p_buffer], p_mipLevel, GL_FALSE, 0, p_access, Config::FramebfrVariables().gl_normal_buffer_internal_format);
+		case GeometryBuffer::GBufferEmissive:
+			glBindImageTexture(p_imageUnitIndex, m_GBTextures[p_buffer], p_mipLevel, GL_FALSE, 0, p_access, Config::FramebfrVariables().gl_emissive_buffer_internal_format);
+			break;
+		case GeometryBuffer::GBufferMatProperties:
+			glBindImageTexture(p_imageUnitIndex, m_GBTextures[p_buffer], p_mipLevel, GL_FALSE, 0, p_access, Config::FramebfrVariables().gl_mat_properties_buffer_internal_format);
+			break;
+		case GeometryBuffer::GBufferFinal:
+			glBindTextureUnit(0, m_finalBuffer);
+			glBindImageTexture(p_imageUnitIndex, m_finalBuffer, p_mipLevel, GL_FALSE, 0, p_access, Config::FramebfrVariables().gl_final_buffer_internal_format);
+			break;
+		case GeometryBuffer::GBufferIntermediate:
+			glBindImageTexture(p_imageUnitIndex, m_intermediateBuffer, p_mipLevel, GL_FALSE, 0, p_access, Config::FramebfrVariables().gl_blur_buffer_internal_format);
+			break;
+		}
+	}
 
 
 	GLuint  m_GBTextures[GBufferNumTextures],	// Geometry pass textures
 	GLuint  m_GBTextures[GBufferNumTextures],	// Geometry pass textures
 			m_intermediateBuffer,				// Intermediate buffer between vertical and horizontal blur passes
 			m_intermediateBuffer,				// Intermediate buffer between vertical and horizontal blur passes

+ 2 - 4
Praxis3D/Source/LenseFlarePass.h

@@ -95,8 +95,6 @@ public:
 		glDisable(GL_DEPTH_TEST);
 		glDisable(GL_DEPTH_TEST);
 
 
 		// Calculate the apsect ratio for the halo
 		// Calculate the apsect ratio for the halo
-
-
 		if(m_currentScreenRes.x != Config::graphicsVar().current_resolution_x || m_currentScreenRes.y != Config::graphicsVar().current_resolution_y)
 		if(m_currentScreenRes.x != Config::graphicsVar().current_resolution_x || m_currentScreenRes.y != Config::graphicsVar().current_resolution_y)
 		{
 		{
 			m_currentScreenRes.x = Config::graphicsVar().current_resolution_x;
 			m_currentScreenRes.x = Config::graphicsVar().current_resolution_x;
@@ -126,8 +124,8 @@ public:
 		glBindTexture(GL_TEXTURE_2D, m_lensFlareGhostGradient.getHandle());
 		glBindTexture(GL_TEXTURE_2D, m_lensFlareGhostGradient.getHandle());
 
 
 		// Perform various visual effects in the post process shader
 		// Perform various visual effects in the post process shader
-		//m_renderer.queueForDrawing(m_lenseFlareShader->getShaderHandle(), m_lenseFlareShader->getUniformUpdater(), p_sceneObjects.m_camera.m_spatialData.m_transformMat);
-		//m_renderer.passScreenSpaceDrawCommandsToBackend();
+		m_renderer.queueForDrawing(m_lenseFlareShader->getShaderHandle(), m_lenseFlareShader->getUniformUpdater(), p_sceneObjects.m_camera.m_spatialData.m_transformMat);
+		m_renderer.passScreenSpaceDrawCommandsToBackend();
 
 
 		p_renderPassData.setBlurInputMap(GeometryBuffer::GBufferDiffuse);
 		p_renderPassData.setBlurInputMap(GeometryBuffer::GBufferDiffuse);
 		p_renderPassData.setBlurOutputMap(GeometryBuffer::GBufferDiffuse);
 		p_renderPassData.setBlurOutputMap(GeometryBuffer::GBufferDiffuse);

+ 45 - 0
Praxis3D/Source/RendererBackend.cpp

@@ -140,3 +140,48 @@ void RendererBackend::processDrawing(const ScreenSpaceDrawCommands &p_screenSpac
 	}
 	}
 }
 }
 
 
+void RendererBackend::processDrawing(const ComputeDispatchCommands &p_computeDispatchCommands, const UniformFrameData &p_frameData)
+{
+	for(decltype(p_computeDispatchCommands.size()) i = 0, size = p_computeDispatchCommands.size(); i < size; i++)
+	{
+		// Get uniform data
+		const UniformObjectData &uniformObjectData = p_computeDispatchCommands[i].m_uniformObjectData;
+
+		// Get various handles
+		const auto shaderHandle = p_computeDispatchCommands[i].m_shaderHandle;
+		const auto &uniformUpdater = p_computeDispatchCommands[i].m_uniformUpdater;
+
+		// Bind the shader
+		bindShader(shaderHandle);
+
+		// Update shader uniforms
+		textureUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+		frameUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+		modelUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+		meshUniformUpdate(shaderHandle, uniformUpdater, uniformObjectData, p_frameData);
+
+		// Launch compute work groups
+		glDispatchCompute(p_computeDispatchCommands[i].m_numOfGroups[0], p_computeDispatchCommands[i].m_numOfGroups[1], p_computeDispatchCommands[i].m_numOfGroups[2]);
+
+		// Determine the memory barrier type
+		GLbitfield memoryBarrierBit = 0;
+		switch(p_computeDispatchCommands[i].m_memoryBarrier)
+		{
+			case MemoryBarrierType::MemoryBarrierType_All:
+				memoryBarrierBit = GL_ALL_BARRIER_BITS;
+				break;
+
+			case MemoryBarrierType::MemoryBarrierType_ImageAccessBarrier:
+				memoryBarrierBit = GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
+				break;
+
+			case MemoryBarrierType::MemoryBarrierType_AccessAndFetchBarrier:
+				memoryBarrierBit = GL_SHADER_IMAGE_ACCESS_BARRIER_BIT | GL_TEXTURE_FETCH_BARRIER_BIT;
+				break;
+		}
+
+		// Define the memory barrier for the data in the compute shader
+		glMemoryBarrier(memoryBarrierBit);
+	}
+}
+

+ 35 - 1
Praxis3D/Source/RendererBackend.h

@@ -107,6 +107,31 @@ public:
 		const unsigned int m_shaderHandle;
 		const unsigned int m_shaderHandle;
 	};
 	};
 
 
+	// A command to execute a compute shader
+	struct ComputeDispatchCommand
+	{
+		ComputeDispatchCommand(const unsigned int p_numOfGroupsX, 
+							   const unsigned int p_numOfGroupsY, 
+							   const unsigned int p_numOfGroupsZ, 
+							   const MemoryBarrierType p_memoryBarrier, 
+							   const ShaderUniformUpdater &p_uniformUpdater,
+							   const UniformObjectData &p_uniformObjectData,
+							   const unsigned int p_shaderHandle) :
+			m_numOfGroups{ p_numOfGroupsX, p_numOfGroupsY, p_numOfGroupsZ },
+			m_memoryBarrier(p_memoryBarrier),
+			m_uniformUpdater(p_uniformUpdater),
+			m_uniformObjectData(p_uniformObjectData),
+			m_shaderHandle(p_shaderHandle) { }
+
+		const unsigned int m_numOfGroups[3];
+		const MemoryBarrierType m_memoryBarrier;
+
+		const ShaderUniformUpdater &m_uniformUpdater;
+		const UniformObjectData m_uniformObjectData;
+
+		const unsigned int m_shaderHandle;
+	};
+
 	// Used for binding textures and framebuffers for reading and writing
 	// Used for binding textures and framebuffers for reading and writing
 	struct BindCommand
 	struct BindCommand
 	{
 	{
@@ -362,6 +387,7 @@ public:
 
 
 	typedef std::vector<LoadCommand> LoadCommands;
 	typedef std::vector<LoadCommand> LoadCommands;
 	typedef std::vector<BufferUpdateCommand> BufferUpdateCommands;
 	typedef std::vector<BufferUpdateCommand> BufferUpdateCommands;
+	typedef std::vector<ComputeDispatchCommand> ComputeDispatchCommands;
 
 
 	RendererBackend();
 	RendererBackend();
 	~RendererBackend();
 	~RendererBackend();
@@ -381,6 +407,7 @@ public:
 	void processLoading(LoadCommands &p_loadCommands, const UniformFrameData &p_frameData);
 	void processLoading(LoadCommands &p_loadCommands, const UniformFrameData &p_frameData);
 	void processDrawing(const DrawCommands &p_drawCommands, const UniformFrameData &p_frameData);
 	void processDrawing(const DrawCommands &p_drawCommands, const UniformFrameData &p_frameData);
 	void processDrawing(const ScreenSpaceDrawCommands &p_screenSpaceDrawCommands, const UniformFrameData &p_frameData);
 	void processDrawing(const ScreenSpaceDrawCommands &p_screenSpaceDrawCommands, const UniformFrameData &p_frameData);
+	void processDrawing(const ComputeDispatchCommands &p_computeDispatchCommands, const UniformFrameData &p_frameData);
 
 
 	inline GeometryBuffer *getGeometryBuffer() { return m_gbuffer; }
 	inline GeometryBuffer *getGeometryBuffer() { return m_gbuffer; }
 
 
@@ -602,6 +629,7 @@ protected:
 		{
 		{
 			unsigned int shaderHandles[ShaderType_NumOfTypes] = {};
 			unsigned int shaderHandles[ShaderType_NumOfTypes] = {};
 			unsigned int shaderTypes[ShaderType_NumOfTypes] = {
 			unsigned int shaderTypes[ShaderType_NumOfTypes] = {
+				GL_COMPUTE_SHADER,
 				GL_FRAGMENT_SHADER,
 				GL_FRAGMENT_SHADER,
 				GL_GEOMETRY_SHADER,
 				GL_GEOMETRY_SHADER,
 				GL_VERTEX_SHADER,
 				GL_VERTEX_SHADER,
@@ -646,8 +674,14 @@ protected:
 			}
 			}
 			else
 			else
 			{
 			{
+				unsigned int numOfShaders = ShaderType::ShaderType_NumOfTypes;
+
+				// If a compute shader exists, then load ONLY the compute shader
+				if(!p_command.m_objectData.m_shaderData.m_source[ShaderType::ShaderType_Compute].empty())
+					numOfShaders = 1;
+
 				// Create individual shaders
 				// Create individual shaders
-				for(unsigned int i = 0; i < ShaderType_NumOfTypes; i++)
+				for(unsigned int i = 0; i < numOfShaders; i++)
 				{
 				{
 					if(!p_command.m_objectData.m_shaderData.m_source[i].empty())
 					if(!p_command.m_objectData.m_shaderData.m_source[i].empty())
 					{
 					{

+ 13 - 7
Praxis3D/Source/RendererFrontend.cpp

@@ -1,6 +1,7 @@
 
 
 #include "AtmScatteringPass.h"
 #include "AtmScatteringPass.h"
 #include "BloomCompositePass.h"
 #include "BloomCompositePass.h"
+#include "BloomPass.h"
 #include "BlurPass.h"
 #include "BlurPass.h"
 #include "GeometryPass.h"
 #include "GeometryPass.h"
 #include "GUIPass.h"
 #include "GUIPass.h"
@@ -14,19 +15,20 @@
 #include "RendererFrontend.h"
 #include "RendererFrontend.h"
 #include "SkyPass.h"
 #include "SkyPass.h"
 
 
-RendererFrontend::RendererFrontend()
+RendererFrontend::RendererFrontend() : m_renderPassData(nullptr)
 {
 {
 	// Set up the order of the rendering passes
 	// Set up the order of the rendering passes
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_Geometry);
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_Geometry);
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_AtmScattering);
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_AtmScattering);
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_Lighting);
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_Lighting);
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_AtmScattering);
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_AtmScattering);
-	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_HdrMapping);
-	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_Blur);
-	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_BloomComposite);
-	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_LenseFlare);
-	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_Blur);
-	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_LenseFlareComposite);
+	//m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_HdrMapping);
+	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_Bloom);
+	//m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_Blur);
+	//m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_BloomComposite);
+	//m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_LenseFlare);
+	//m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_Blur);
+	//m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_LenseFlareComposite);
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_Final);
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_Final);
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_GUI);
 	m_renderingPassesTypes.push_back(RenderPassType::RenderPassType_GUI);
 
 
@@ -59,6 +61,10 @@ RendererFrontend::RendererFrontend()
 			if(m_initializedRenderingPasses[RenderPassType_Blur] == nullptr)
 			if(m_initializedRenderingPasses[RenderPassType_Blur] == nullptr)
 				m_initializedRenderingPasses[RenderPassType_Blur] = new BlurPass(*this);
 				m_initializedRenderingPasses[RenderPassType_Blur] = new BlurPass(*this);
 			break;
 			break;
+		case RenderPassType_Bloom:
+			if(m_initializedRenderingPasses[RenderPassType_Bloom] == nullptr)
+				m_initializedRenderingPasses[RenderPassType_Bloom] = new BloomPass(*this);
+			break;
 		case RenderPassType_BloomComposite:
 		case RenderPassType_BloomComposite:
 			if(m_initializedRenderingPasses[RenderPassType_BloomComposite] == nullptr)
 			if(m_initializedRenderingPasses[RenderPassType_BloomComposite] == nullptr)
 				m_initializedRenderingPasses[RenderPassType_BloomComposite] = new BloomCompositePass(*this);
 				m_initializedRenderingPasses[RenderPassType_BloomComposite] = new BloomCompositePass(*this);

+ 30 - 2
Praxis3D/Source/RendererFrontend.h

@@ -12,6 +12,7 @@ class RendererFrontend
 {
 {
 	friend class AtmScatteringPass;
 	friend class AtmScatteringPass;
 	friend class BloomCompositePass;
 	friend class BloomCompositePass;
+	friend class BloomPass;
 	friend class BlurPass;
 	friend class BlurPass;
 	friend class GeometryPass;
 	friend class GeometryPass;
 	friend class GUIPass;
 	friend class GUIPass;
@@ -125,6 +126,24 @@ protected:
 				objectData,
 				objectData,
 				p_shaderHandle)
 				p_shaderHandle)
 			);
 			);
+	}	
+	inline void queueForDrawing(const unsigned int p_shaderHandle, const ShaderUniformUpdater &p_uniformUpdater, const glm::mat4 &p_viewProjMatrix, const unsigned int p_numOfGroupsX, const unsigned int p_numOfGroupsY, const unsigned int p_numOfGroupsZ, const MemoryBarrierType p_memoryBarrier)
+	{
+		// Assign the object data that is later passed to the shaders
+		const UniformObjectData objectData(p_viewProjMatrix,
+										   p_viewProjMatrix,
+										   Config::graphicsVar().height_scale,
+										   Config::graphicsVar().alpha_threshold,
+										   Config::graphicsVar().emissive_threshold,
+										   Config::graphicsVar().texture_tiling_factor);
+
+		m_computeDispatchCommands.emplace_back(p_numOfGroupsX,
+											   p_numOfGroupsY,
+											   p_numOfGroupsZ, 
+											   p_memoryBarrier,
+											   p_uniformUpdater,
+											   objectData,
+											   p_shaderHandle);
 	}
 	}
 
 
 	inline void queueForLoading(ShaderLoader::ShaderProgram &p_shader)
 	inline void queueForLoading(ShaderLoader::ShaderProgram &p_shader)
@@ -238,6 +257,14 @@ protected:
 
 
 		// Clear draw commands
 		// Clear draw commands
 		m_screenSpaceDrawCommands.clear();
 		m_screenSpaceDrawCommands.clear();
+	}	
+	inline void passComputeDispatchCommandsToBackend()
+	{
+		// Pass the queued compute shader dispatch commands to the backend to be sent to GPU
+		m_backend.processDrawing(m_computeDispatchCommands, m_frameData);
+
+		// Clear compute dispatch commands
+		m_computeDispatchCommands.clear();
 	}
 	}
 	inline void passUpdateCommandsToBackend()
 	inline void passUpdateCommandsToBackend()
 	{
 	{
@@ -284,8 +311,9 @@ protected:
 	RendererBackend::LoadCommands m_loadCommands;
 	RendererBackend::LoadCommands m_loadCommands;
 	RendererBackend::BufferUpdateCommands m_bufferUpdateCommands;
 	RendererBackend::BufferUpdateCommands m_bufferUpdateCommands;
 	RendererBackend::ScreenSpaceDrawCommands m_screenSpaceDrawCommands;
 	RendererBackend::ScreenSpaceDrawCommands m_screenSpaceDrawCommands;
+	RendererBackend::ComputeDispatchCommands m_computeDispatchCommands;
 
 
-	// Holds info used between rendering passses
+	// Holds info used between rendering passes
 	RenderPassData *m_renderPassData;
 	RenderPassData *m_renderPassData;
 
 
 	// View - projection matrix
 	// View - projection matrix
@@ -296,5 +324,5 @@ protected:
 
 
 	std::vector<RenderPassType> m_renderingPassesTypes;
 	std::vector<RenderPassType> m_renderingPassesTypes;
 	RenderPass *m_initializedRenderingPasses[RenderPassType::RenderPassType_NumOfTypes];
 	RenderPass *m_initializedRenderingPasses[RenderPassType::RenderPassType_NumOfTypes];
-	bool m_renderPassBeingUsed[RenderPassType::RenderPassType_NumOfTypes];
+	//bool m_renderPassBeingUsed[RenderPassType::RenderPassType_NumOfTypes];
 };
 };

+ 8 - 0
Praxis3D/Source/ShaderLoader.cpp

@@ -59,6 +59,11 @@ ShaderLoader::ShaderProgram *ShaderLoader::load(const PropertySet &p_properties)
 				programName = p_properties[i].getString();
 				programName = p_properties[i].getString();
 				break;
 				break;
 
 
+			case Properties::ComputeShader:
+				shaderFilename[ShaderType_Compute] = p_properties[i].getString();
+				numberOfShaders++;
+				break;
+
 			case Properties::FragmentShader:
 			case Properties::FragmentShader:
 				shaderFilename[ShaderType_Fragment] = p_properties[i].getString();
 				shaderFilename[ShaderType_Fragment] = p_properties[i].getString();
 				numberOfShaders++;
 				numberOfShaders++;
@@ -128,6 +133,9 @@ ShaderLoader::ShaderProgram *ShaderLoader::load(const PropertySet &p_properties)
 				if(!shaderFilename[shaderType].empty())
 				if(!shaderFilename[shaderType].empty())
 					newProgram->addShader(static_cast<ShaderType>(shaderType), shaderFilename[shaderType]);
 					newProgram->addShader(static_cast<ShaderType>(shaderType), shaderFilename[shaderType]);
 
 
+			// If there is a compute shader source code loaded, mark the shader program as compute only
+			if(!newProgram->m_shaderSource[ShaderType::ShaderType_Compute].empty())
+				newProgram->m_computeShader = true;
 
 
 			// Create a uniform updater for the new shader
 			// Create a uniform updater for the new shader
 			newProgram->m_uniformUpdater = new ShaderUniformUpdater(*newProgram);
 			newProgram->m_uniformUpdater = new ShaderUniformUpdater(*newProgram);

+ 5 - 2
Praxis3D/Source/ShaderLoader.h

@@ -25,12 +25,13 @@ public:
 		enum ShaderType : unsigned int
 		enum ShaderType : unsigned int
 		{
 		{
 			ShaderNull = 0,
 			ShaderNull = 0,
+			ShaderCompute,
 			ShaderFragment,
 			ShaderFragment,
 			ShaderGeometry,
 			ShaderGeometry,
 			ShaderVertex,
 			ShaderVertex,
 			ShaderTessControl,
 			ShaderTessControl,
 			ShaderTessEvaluation,
 			ShaderTessEvaluation,
-			ShaderNumOfTypes = 5
+			ShaderNumOfTypes = 6
 		};
 		};
 
 
 	public:
 	public:
@@ -243,6 +244,7 @@ public:
 			m_combinedFilename = p_filename;
 			m_combinedFilename = p_filename;
 			m_filenameHash = p_filenameHashkey > 0 ? p_filenameHashkey : Utilities::getHashKey(p_filename);
 			m_filenameHash = p_filenameHashkey > 0 ? p_filenameHashkey : Utilities::getHashKey(p_filename);
 			m_tessellated = false;
 			m_tessellated = false;
+			m_computeShader = false;
 			m_defaultShader = false;
 			m_defaultShader = false;
 			m_loadedToMemory = false;
 			m_loadedToMemory = false;
 			m_loadedToVideoMemory = false;
 			m_loadedToVideoMemory = false;
@@ -256,7 +258,8 @@ public:
 		bool	m_defaultShader, 
 		bool	m_defaultShader, 
 				m_loadedToMemory,
 				m_loadedToMemory,
 				m_loadedToVideoMemory,
 				m_loadedToVideoMemory,
-				m_tessellated;
+				m_tessellated,
+				m_computeShader;
 
 
 		std::string m_combinedFilename;
 		std::string m_combinedFilename;
 		std::string m_shaderFilename[ShaderType_NumOfTypes];
 		std::string m_shaderFilename[ShaderType_NumOfTypes];

+ 7 - 0
Praxis3D/Source/ShaderUniformUpdater.cpp

@@ -137,6 +137,11 @@ ErrorCode ShaderUniformUpdater::generatePerFrameList()
 	uniformList.push_back(new EmissiveMultiplierUniform(m_shaderHandle));
 	uniformList.push_back(new EmissiveMultiplierUniform(m_shaderHandle));
 	uniformList.push_back(new LODParallaxMappingUniform(m_shaderHandle));
 	uniformList.push_back(new LODParallaxMappingUniform(m_shaderHandle));
 
 
+	// Bloom
+	uniformList.push_back(new BloomDirtIntensityUniform(m_shaderHandle));
+	uniformList.push_back(new BloomIntensityUniform(m_shaderHandle));
+	uniformList.push_back(new BloomTresholdUniform(m_shaderHandle));
+
 	// Go through each uniform and check if it is valid
 	// Go through each uniform and check if it is valid
 	// If it is, add it to the update list, if not, delete it
 	// If it is, add it to the update list, if not, delete it
 	for(decltype(uniformList.size()) i = 0, size = uniformList.size(); i < size; i++)
 	for(decltype(uniformList.size()) i = 0, size = uniformList.size(); i < size; i++)
@@ -168,6 +173,8 @@ ErrorCode ShaderUniformUpdater::generatePerModelList()
 	uniformList.push_back(new AlphaThresholdUniform(m_shaderHandle));
 	uniformList.push_back(new AlphaThresholdUniform(m_shaderHandle));
 	uniformList.push_back(new EmissiveThresholdUniform(m_shaderHandle));
 	uniformList.push_back(new EmissiveThresholdUniform(m_shaderHandle));
 	uniformList.push_back(new HeightScaleUniform(m_shaderHandle));
 	uniformList.push_back(new HeightScaleUniform(m_shaderHandle));
+	uniformList.push_back(new MipLevelUniform(m_shaderHandle));
+	uniformList.push_back(new TexelSizeUniform(m_shaderHandle));
 	uniformList.push_back(new TextureTilingFactorUniform(m_shaderHandle));
 	uniformList.push_back(new TextureTilingFactorUniform(m_shaderHandle));
 
 
 	// Test uniforms, used for debugging, etc
 	// Test uniforms, used for debugging, etc

+ 1 - 0
Praxis3D/Source/ShaderUniformUpdater.h

@@ -22,6 +22,7 @@ public:
 		m_numTextureUpdates = 0;
 		m_numTextureUpdates = 0;
 		m_numUniformBlockUpdates = 0;
 		m_numUniformBlockUpdates = 0;
 		m_numSSBBBlockUpdates = 0;
 		m_numSSBBBlockUpdates = 0;
+		m_shaderHandle = 0;
 	}
 	}
 	~ShaderUniformUpdater()
 	~ShaderUniformUpdater()
 	{
 	{

+ 88 - 0
Praxis3D/Source/ShaderUniforms.h

@@ -432,6 +432,94 @@ public:
 private:
 private:
 	float parallaxLOD;
 	float parallaxLOD;
 };
 };
+class TexelSizeUniform : public BaseUniform
+{
+public:
+	TexelSizeUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().texelSize, p_shaderHandle)
+	{
+	}
+
+	void update(const UniformData &p_uniformData)
+	{
+		glUniform2f(m_uniformHandle, p_uniformData.m_frameData.m_texelSize.x, p_uniformData.m_frameData.m_texelSize.y);
+	}
+};
+class MipLevelUniform : public BaseUniform
+{
+public:
+	MipLevelUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().mipLevel, p_shaderHandle)
+	{
+	}
+
+	void update(const UniformData &p_uniformData)
+	{
+		glUniform1i(m_uniformHandle, p_uniformData.m_frameData.m_mipLevel);
+	}
+};
+
+class BloomTresholdUniform : public BaseUniform
+{
+public:
+	BloomTresholdUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().bloomTreshold, p_shaderHandle)
+	{
+	}
+
+	void update(const UniformData &p_uniformData)
+	{
+		// Check if the same value is not already assigned (a small optimization)
+		if(m_bloomTreshold != p_uniformData.m_frameData.m_bloomTreshold)
+		{
+			m_bloomTreshold = p_uniformData.m_frameData.m_bloomTreshold;
+
+			glUniform4f(m_uniformHandle, m_bloomTreshold.x, m_bloomTreshold.y, m_bloomTreshold.z, m_bloomTreshold.w);
+		}
+	}
+
+private:
+	glm::vec4 m_bloomTreshold;
+};
+class BloomDirtIntensityUniform : public BaseUniform
+{
+public:
+	BloomDirtIntensityUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().bloomDirtIntensity, p_shaderHandle), m_bloomDirtIntensity(0.0f)
+	{
+	}
+
+	void update(const UniformData &p_uniformData)
+	{
+		// Check if the same value is not already assigned (a small optimization)
+		if(m_bloomDirtIntensity != Config::graphicsVar().bloom_dirt_intensity)
+		{
+			m_bloomDirtIntensity = Config::graphicsVar().bloom_dirt_intensity;
+
+			glUniform1f(m_uniformHandle, m_bloomDirtIntensity);
+		}
+	}
+
+private:
+	float m_bloomDirtIntensity;
+};
+class BloomIntensityUniform : public BaseUniform
+{
+public:
+	BloomIntensityUniform(unsigned int p_shaderHandle) : BaseUniform(Config::shaderVar().bloomIntensity, p_shaderHandle), m_bloomIntensity(0.0f)
+	{
+	}
+
+	void update(const UniformData &p_uniformData)
+	{
+		// Check if the same value is not already assigned (a small optimization)
+		if(m_bloomIntensity != Config::graphicsVar().bloom_intensity)
+		{
+			m_bloomIntensity = Config::graphicsVar().bloom_intensity;
+
+			glUniform1f(m_uniformHandle, m_bloomIntensity);
+		}
+	}
+
+private:
+	float m_bloomIntensity;
+};
 
 
 class DirLightColorUniform : public BaseUniform
 class DirLightColorUniform : public BaseUniform
 {
 {

+ 9 - 0
Praxis3D/Source/UniformData.h

@@ -9,6 +9,8 @@ struct UniformFrameData
 		m_dirLightIntensity = 0.0f;
 		m_dirLightIntensity = 0.0f;
 		m_numPointLights = 0;
 		m_numPointLights = 0;
 		m_numSpotLights = 0;
 		m_numSpotLights = 0;
+		m_deltaTime = 0.0f;
+		m_mipLevel = 1;
 	}
 	}
 
 
 	// Framebuffer size (can be different from the window size)
 	// Framebuffer size (can be different from the window size)
@@ -38,6 +40,13 @@ struct UniformFrameData
 	// Current number of lights in the light buffers
 	// Current number of lights in the light buffers
 	unsigned int m_numPointLights,
 	unsigned int m_numPointLights,
 				 m_numSpotLights;
 				 m_numSpotLights;
+
+	// Bloom pass data
+	glm::vec4 m_bloomTreshold;
+
+	// Misc
+	glm::vec2 m_texelSize;
+	int m_mipLevel;
 };
 };
 
 
 struct UniformObjectData
 struct UniformObjectData