Browse Source

Hooked up SSAO with indirect diffuse and specular
Added a DebugDraw system for easier debug drawing

BearishSun 8 years ago
parent
commit
565a72c133

+ 4 - 0
Data/Raw/Engine/DataList.json

@@ -357,6 +357,10 @@
         {
         {
             "Path": "Clear.bsl",
             "Path": "Clear.bsl",
             "UUID": "5a325167-5bab-4925-8b50-95434448930f"
             "UUID": "5a325167-5bab-4925-8b50-95434448930f"
+        },
+        {
+            "Path": "DebugDraw.bsl",
+            "UUID": "6d3eb44e-b7e9-4c5a-8f8c-e5695607ca13"
         }
         }
     ],
     ],
     "Skin": [
     "Skin": [

+ 12 - 3
Data/Raw/Engine/Includes/ImageBasedLighting.bslinc

@@ -24,10 +24,12 @@ mixin ImageBasedLighting
 	
 	
 		TextureCube gSkyReflectionTex;
 		TextureCube gSkyReflectionTex;
 		SamplerState gSkyReflectionSamp;
 		SamplerState gSkyReflectionSamp;
-		
+				
 		TextureCubeArray gReflProbeCubemaps;
 		TextureCubeArray gReflProbeCubemaps;
 		SamplerState gReflProbeSamp;
 		SamplerState gReflProbeSamp;
 		
 		
+		Texture2D gAmbientOcclusionTex;
+		
 		Texture2D gPreintegratedEnvBRDF;
 		Texture2D gPreintegratedEnvBRDF;
 		SamplerState gPreintegratedEnvBRDFSamp;
 		SamplerState gPreintegratedEnvBRDFSamp;
 		
 		
@@ -186,7 +188,13 @@ mixin ImageBasedLighting
 			return output;
 			return output;
 		}
 		}
 		
 		
-		float3 getImageBasedSpecular(float3 worldPos, float3 V, float3 R, SurfaceData surfaceData, uint probeOffset, uint numProbes)
+		float getSpecularOcclusion(float NoV, float r, float ao)
+		{
+			float r2 = r * r;
+			return saturate(pow(NoV + ao, r2) - 1.0f + ao);
+		}		
+		
+		float3 getImageBasedSpecular(float3 worldPos, float3 V, float3 R, SurfaceData surfaceData, float ao, uint probeOffset, uint numProbes)
 		{
 		{
 			// See C++ code for generation of gPreintegratedEnvBRDF to see why this code works as is
 			// See C++ code for generation of gPreintegratedEnvBRDF to see why this code works as is
 			float3 N = surfaceData.worldNormal.xyz;
 			float3 N = surfaceData.worldNormal.xyz;
@@ -198,8 +206,9 @@ mixin ImageBasedLighting
 			float3 radiance = gatherReflectionRadiance(worldPos, R, surfaceData.roughness, specularColor, probeOffset, numProbes);
 			float3 radiance = gatherReflectionRadiance(worldPos, R, surfaceData.roughness, specularColor, probeOffset, numProbes);
 			
 			
 			float2 envBRDF = gPreintegratedEnvBRDF.SampleLevel(gPreintegratedEnvBRDFSamp, float2(NoV, surfaceData.roughness), 0).rg;
 			float2 envBRDF = gPreintegratedEnvBRDF.SampleLevel(gPreintegratedEnvBRDFSamp, float2(NoV, surfaceData.roughness), 0).rg;
+			float specOcclusion = getSpecularOcclusion(NoV, surfaceData.roughness * surfaceData.roughness, ao);
 			
 			
-			return radiance * (specularColor * envBRDF.x + envBRDF.y);
+			return radiance * (specularColor * envBRDF.x + envBRDF.y) * specOcclusion;
 		}		
 		}		
 	};
 	};
 };
 };

+ 80 - 0
Data/Raw/Engine/Shaders/DebugDraw.bsl

@@ -0,0 +1,80 @@
+technique DebugDraw
+{
+	#ifdef LINE
+	raster
+	{
+		multisample = false; // This controls line rendering algorithm
+		lineaa = true;
+	};
+
+	blend
+	{
+		target
+		{
+			enabled = true;
+			color = { srcA, srcIA, add };
+		};
+	};
+	#endif
+	
+	#ifdef WIRE
+	raster
+	{
+		fill = wire;
+	};
+	#endif
+	
+	code
+	{
+		#ifndef LINE
+			#define LINE 0
+		#endif
+		
+		#ifndef WIRE
+			#define WIRE 0
+		#endif
+	
+		cbuffer Params
+		{
+			float4x4 	gMatViewProj;
+			float4		gViewDir;
+		}
+		
+		#if LINE || WIRE
+		void vsmain(
+			in float3 inPos : POSITION,
+			in float4 color : COLOR0,
+			out float4 oPosition : SV_Position,
+			out float4 oColor : COLOR0)
+		{
+			oPosition = mul(gMatViewProj, float4(inPos.xyz, 1));
+			oColor = color;
+		}
+
+		float4 fsmain(in float4 inPos : SV_Position, in float4 color : COLOR0) : SV_Target
+		{
+			return color;
+		}
+		#else
+		void vsmain(
+			in float3 inPos : POSITION,
+			in float3 inNormal : NORMAL,
+			in float4 color : COLOR0,
+			out float4 oPosition : SV_Position,
+			out float3 oNormal : NORMAL,
+			out float4 oColor : COLOR0)
+		{
+			oPosition = mul(gMatViewProj, float4(inPos.xyz, 1));
+			oNormal = inNormal;
+			oColor = color;
+		}
+		float4 fsmain(in float4 inPos : SV_Position, in float3 normal : NORMAL, in float4 color : COLOR0) : SV_Target
+		{
+			float4 outColor = color * dot(normalize(normal), -gViewDir);
+			outColor.a = color.a;
+			
+			return outColor;
+		}
+		#endif
+	};
+};

+ 9 - 5
Data/Raw/Engine/Shaders/IrradianceEvaluate.bsl

@@ -45,7 +45,8 @@ technique IrradianceEvaluate
 		StructuredBuffer<TetrahedronFace> gTetFaces;
 		StructuredBuffer<TetrahedronFace> gTetFaces;
 		
 		
 		TextureCube gSkyIrradianceTex;
 		TextureCube gSkyIrradianceTex;
-		SamplerState gSkyIrradianceSamp;
+		Texture2D gAmbientOcclusionTex;
+		SamplerState gLinearSamp;
 
 
 		cbuffer Params
 		cbuffer Params
 		{
 		{
@@ -55,7 +56,7 @@ technique IrradianceEvaluate
 		
 		
 		float3 getSkyIndirectDiffuse(float3 dir)
 		float3 getSkyIndirectDiffuse(float3 dir)
 		{
 		{
-			return gSkyIrradianceTex.SampleLevel(gSkyIrradianceSamp, dir, 0).rgb * gSkyBrightness;
+			return gSkyIrradianceTex.SampleLevel(gLinearSamp, dir, 0).rgb * gSkyBrightness;
 		}
 		}
 		
 		
 		float evaluateLambert(SHVector3 coeffs)
 		float evaluateLambert(SHVector3 coeffs)
@@ -176,7 +177,7 @@ technique IrradianceEvaluate
 			
 			
 			float3 irradiance = 0;
 			float3 irradiance = 0;
 			#if SKY_ONLY
 			#if SKY_ONLY
-				irradiance = gSkyIrradianceTex.SampleLevel(gSkyIrradianceSamp, surfaceData.worldNormal, 0).rgb * gSkyBrightness;
+				irradiance = gSkyIrradianceTex.SampleLevel(gLinearSamp, surfaceData.worldNormal, 0).rgb * gSkyBrightness;
 			#else
 			#else
 				uint volumeIdx;
 				uint volumeIdx;
 				#if MSAA_COUNT > 1
 				#if MSAA_COUNT > 1
@@ -186,7 +187,7 @@ technique IrradianceEvaluate
 				#endif
 				#endif
 				
 				
 				if(volumeIdx == 0xFFFF) // Using 16-bit texture, so need to compare like this
 				if(volumeIdx == 0xFFFF) // Using 16-bit texture, so need to compare like this
-					irradiance = gSkyIrradianceTex.SampleLevel(gSkyIrradianceSamp, surfaceData.worldNormal, 0).rgb * gSkyBrightness;
+					irradiance = gSkyIrradianceTex.SampleLevel(gLinearSamp, surfaceData.worldNormal, 0).rgb * gSkyBrightness;
 				else
 				else
 				{
 				{
 					Tetrahedron volume = gTetrahedra[volumeIdx];
 					Tetrahedron volume = gTetrahedra[volumeIdx];
@@ -247,7 +248,10 @@ technique IrradianceEvaluate
 				}
 				}
 			#endif // SKY_ONLY
 			#endif // SKY_ONLY
 			
 			
-			return irradiance * surfaceData.albedo.rgb;
+			float2 uv = NDCToUV(input.screenPos);
+			float ao = gAmbientOcclusionTex.Sample(gLinearSamp, uv);
+			
+			return irradiance * surfaceData.albedo.rgb * ao;
 		}	
 		}	
 	};
 	};
 };
 };

+ 1 - 1
Data/Raw/Engine/Shaders/PPSSAO.bsl

@@ -252,7 +252,7 @@ technique PPSSAO
 			output = lerp(output, 1.0f, saturate(-sceneDepth * gFadeMultiplyAdd.x + gFadeMultiplyAdd.y));
 			output = lerp(output, 1.0f, saturate(-sceneDepth * gFadeMultiplyAdd.x + gFadeMultiplyAdd.y));
 			
 			
 			// Adjust power and intensity
 			// Adjust power and intensity
-			output = 1.0f - saturate(pow(1.0f - output, gPower) * gIntensity);
+			output = 1.0f - saturate((1.0f - pow(output, gPower)) * gIntensity);
 			#endif
 			#endif
 			
 			
 			// On quality 0 we don't blur at all. At qualities higher than 1 we use a proper bilateral blur.
 			// On quality 0 we don't blur at all. At qualities higher than 1 we use a proper bilateral blur.

+ 2 - 1
Data/Raw/Engine/Shaders/TiledDeferredImageBasedLighting.bsl

@@ -164,7 +164,8 @@ technique TiledDeferredImageBasedLighting
 			existingColor = gInColor.Load(int3(pixelPos.xy, 0));
 			existingColor = gInColor.Load(int3(pixelPos.xy, 0));
 			#endif				
 			#endif				
 			
 			
-			float3 imageBasedSpecular = getImageBasedSpecular(worldPosition, V, specR, surfaceData, probeOffset, numProbes);
+			float ao = gAmbientOcclusionTex.Load(int3(pixelPos.xy, 0));
+			float3 imageBasedSpecular = getImageBasedSpecular(worldPosition, V, specR, surfaceData, ao, probeOffset, numProbes);
 
 
 			float4 totalLighting = existingColor;
 			float4 totalLighting = existingColor;
 			totalLighting.rgb += imageBasedSpecular;
 			totalLighting.rgb += imageBasedSpecular;

+ 2 - 1
Data/Raw/Engine/Shaders/Transparent.bsl

@@ -82,7 +82,8 @@ mixin Surface
 			float3 specR = getSpecularDominantDir(N, R, surfaceData.roughness);
 			float3 specR = getSpecularDominantDir(N, R, surfaceData.roughness);
 			
 			
 			float4 directLighting = getDirectLighting(input.worldPosition, V, specR, surfaceData, lightOffsets);
 			float4 directLighting = getDirectLighting(input.worldPosition, V, specR, surfaceData, lightOffsets);
-			float3 imageBasedSpecular = getImageBasedSpecular(input.worldPosition, V, specR, surfaceData, 
+			float ao = gAmbientOcclusionTex.Sample(gAlbedoSamp, input.uv0);
+			float3 imageBasedSpecular = getImageBasedSpecular(input.worldPosition, V, specR, surfaceData, ao, 
 				reflProbeOffsetAndSize.x, reflProbeOffsetAndSize.y);
 				reflProbeOffsetAndSize.x, reflProbeOffsetAndSize.y);
 
 
 			float3 totalLighting = directLighting.rgb;
 			float3 totalLighting = directLighting.rgb;

+ 3 - 0
Source/BansheeCore/Include/BsCLightProbeVolume.h

@@ -36,6 +36,9 @@ namespace bs
 		/** @copydoc LightProbeVolume::removeProbe() */
 		/** @copydoc LightProbeVolume::removeProbe() */
 		void removeProbe(UINT32 handle) { mInternal->removeProbe(handle); }
 		void removeProbe(UINT32 handle) { mInternal->removeProbe(handle); }
 
 
+		/** @copydoc LightProbeVolume::getProbes() */
+		Vector<LightProbeInfo> getProbes() const;
+
 		/** @copydoc LightProbeVolume::renderProbe() */
 		/** @copydoc LightProbeVolume::renderProbe() */
 		void renderProbe(UINT32 handle);
 		void renderProbe(UINT32 handle);
 
 

+ 12 - 1
Source/BansheeCore/Include/BsLightProbeVolume.h

@@ -89,6 +89,14 @@ namespace bs
 		LightProbeSHCoefficients coefficients;
 		LightProbeSHCoefficients coefficients;
 	};
 	};
 
 
+	/** Information about a single probe in the light probe volume. */
+	struct LightProbeInfo
+	{
+		UINT32 handle;
+		Vector3 position;
+		LightProbeSHCoefficients shCoefficients;
+	};
+
 	/** 
 	/** 
 	 * Allows you to define a volume of light probes that will be used for indirect lighting. Lighting information in the
 	 * Allows you to define a volume of light probes that will be used for indirect lighting. Lighting information in the
 	 * scene will be interpolated from nearby probes to calculate the amount of indirect lighting at that position. It is
 	 * scene will be interpolated from nearby probes to calculate the amount of indirect lighting at that position. It is
@@ -130,6 +138,9 @@ namespace bs
 		 */
 		 */
 		void removeProbe(UINT32 handle);
 		void removeProbe(UINT32 handle);
 
 
+		/** Returns a list of positions of all light probes in the volume. */
+		Vector<LightProbeInfo> getProbes() const;
+
 		/**
 		/**
 		 * Causes the information for this specific light probe to be updated. You generally want to call this when the
 		 * Causes the information for this specific light probe to be updated. You generally want to call this when the
 		 * probe is moved or the scene around the probe changes.
 		 * probe is moved or the scene around the probe changes.
@@ -199,7 +210,7 @@ namespace bs
 
 
 		/** 
 		/** 
 		 * Fetches latest SH coefficient data from the core thread. Note this method will block the caller thread until
 		 * Fetches latest SH coefficient data from the core thread. Note this method will block the caller thread until
-		 * the data is fetched from the core thread. It will also force any in-progress light probe updated to finish.
+		 * the data is fetched from the core thread. It will also force any in-progress light probe updates to finish.
 		 */
 		 */
 		void updateCoefficients();
 		void updateCoefficients();
 
 

+ 8 - 0
Source/BansheeCore/Source/BsCLightProbeVolume.cpp

@@ -43,6 +43,14 @@ namespace bs
 		}
 		}
 	}
 	}
 
 
+	Vector<LightProbeInfo> CLightProbeVolume::getProbes() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->getProbes();
+
+		return Vector<LightProbeInfo>();
+	}
+
 	void CLightProbeVolume::onInitialized()
 	void CLightProbeVolume::onInitialized()
 	{
 	{
 		// If mInternal already exists this means this object was deserialized,
 		// If mInternal already exists this means this object was deserialized,

+ 20 - 0
Source/BansheeCore/Source/BsLightProbeVolume.cpp

@@ -70,6 +70,26 @@ namespace bs
 		return Vector3::ZERO;
 		return Vector3::ZERO;
 	}
 	}
 
 
+	Vector<LightProbeInfo> LightProbeVolume::getProbes() const
+	{
+		Vector<LightProbeInfo> output;
+
+		for(auto& entry : mProbes)
+		{
+			if (entry.second.flags == LightProbeFlags::Removed || entry.second.flags == LightProbeFlags::Empty)
+				continue;
+
+			LightProbeInfo info;
+			info.position = entry.second.position;
+			info.handle = entry.first;
+			info.shCoefficients = entry.second.coefficients;
+
+			output.push_back(info);
+		}
+
+		return output;		
+	}
+
 	void LightProbeVolume::resize(const AABox& volume, const Vector3I& cellCount)
 	void LightProbeVolume::resize(const AABox& volume, const Vector3I& cellCount)
 	{
 	{
 		UINT32 numProbesX = std::max(1, mCellCount.v[0]) + 1;
 		UINT32 numProbesX = std::max(1, mCellCount.v[0]) + 1;

+ 2 - 0
Source/BansheeEngine/CMakeSources.cmake

@@ -110,6 +110,7 @@ set(BS_BANSHEEENGINE_SRC_UTILITY
 	"Source/BsPaths.cpp"
 	"Source/BsPaths.cpp"
 	"Source/BsShapeMeshes2D.cpp"
 	"Source/BsShapeMeshes2D.cpp"
 	"Source/BsShapeMeshes3D.cpp"
 	"Source/BsShapeMeshes3D.cpp"
+	"Source/BsDebugDraw.cpp"
 )
 )
 
 
 set(BS_BANSHEEENGINE_INC_2D
 set(BS_BANSHEEENGINE_INC_2D
@@ -165,6 +166,7 @@ set(BS_BANSHEEENGINE_INC_UTILITY
 	"Include/BsRectOffset.h"
 	"Include/BsRectOffset.h"
 	"Include/BsShapeMeshes2D.h"
 	"Include/BsShapeMeshes2D.h"
 	"Include/BsShapeMeshes3D.h"
 	"Include/BsShapeMeshes3D.h"
+	"Include/BsDebugDraw.h"
 )
 )
 
 
 set(BS_BANSHEEENGINE_SRC_RENDERER
 set(BS_BANSHEEENGINE_SRC_RENDERER

+ 238 - 0
Source/BansheeEngine/Include/BsDebugDraw.h

@@ -0,0 +1,238 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsModule.h"
+#include "BsDrawHelper.h"
+#include "BsParamBlocks.h"
+#include "BsRendererExtension.h"
+#include "BsRendererMaterial.h"
+
+namespace bs
+{
+	namespace ct { class DebugDrawRenderer; }
+
+	/** @addtogroup Utility-Engine
+	 *  @{
+	 */
+
+	/**	Supported types of materials (shaders) by DebugDraw. */
+	enum class DebugDrawMaterial
+	{
+		Solid, Wire, Line
+	};
+
+	/** Provides an easy access to draw basic 2D and 3D shapes, primarily meant for debugging purposes. */
+	class BS_EXPORT DebugDraw : public Module<DebugDraw>
+	{
+	public:
+		DebugDraw();
+		~DebugDraw();
+
+		/**	Changes the color of any further draw calls. */
+		void setColor(const Color& color);
+
+		/**	Changes the transform that will be applied to meshes of any further draw calls.  */
+		void setTransform(const Matrix4& transform);
+
+		/**
+		 * Draws an axis aligned cuboid.
+		 *
+		 * @param[in]	position	Center of the cuboid.
+		 * @param[in]	extents		Radius of the cuboid in each axis.
+		 */
+		void drawCube(const Vector3& position, const Vector3& extents);
+
+		/** Draws a sphere. */
+		void drawSphere(const Vector3& position, float radius);
+
+		/**
+		 * Draws a solid cone.
+		 *
+		 * @param[in]	base		Position of the center of the base of the cone.
+		 * @param[in]	normal		Orientation of the cone, pointing from center base to the tip of the cone.
+		 * @param[in]	height		Height of the cone (along the normal).
+		 * @param[in]	radius		Radius of the base of the cone.
+		 * @param[in]	scale		Scale applied to cone's disc width & height. Allows you to create elliptical cones.
+		 */
+		void drawCone(const Vector3& base, const Vector3& normal, float height, float radius, 
+			const Vector2& scale = Vector2::ONE);
+
+		/**
+		 * Draws a solid disc.
+		 *
+		 * @param[in]	position	Center of the disc.
+		 * @param[in]	normal		Orientation of the disc, pointing in the direction the disc is visible in.
+		 * @param[in]	radius		Radius of the disc.
+		 */
+		void drawDisc(const Vector3& position, const Vector3& normal, float radius);
+
+		/**
+		 * Draws a wireframe axis aligned cuboid.
+		 *
+		 * @param[in]	position	Center of the cuboid.
+		 * @param[in]	extents		Radius of the cuboid in each axis.
+		 */
+		void drawWireCube(const Vector3& position, const Vector3& extents);
+
+		/** Draws a wireframe sphere represented by three discs. */
+		void drawWireSphere(const Vector3& position, float radius);
+
+		/**
+		 * Draws a wireframe cone.
+		 *
+		 * @param[in]	base		Position of the center of the base of the cone.
+		 * @param[in]	normal		Orientation of the cone, pointing from center base to the tip of the cone.
+		 * @param[in]	height		Height of the cone (along the normal).
+		 * @param[in]	radius		Radius of the base of the cone.
+		 * @param[in]	scale		Scale applied to cone's disc width & height. Allows you to create elliptical cones.
+		 */
+		void drawWireCone(const Vector3& base, const Vector3& normal, float height, float radius, 
+			const Vector2& scale = Vector2::ONE);
+
+		/** Draws a line between two points. */
+		void drawLine(const Vector3& start, const Vector3& end);
+
+		/**
+		 * Draws a list of lines. Provided array must contain pairs of the line start point followed by an end point.
+		 */
+		void drawLineList(const Vector<Vector3>& linePoints);
+
+		/**
+		 * Draws a wireframe disc.
+		 *
+		 * @param[in]	position	Center of the disc.
+		 * @param[in]	normal		Orientation of the disc, pointing in the direction the disc is visible in.
+		 * @param[in]	radius		Radius of the disc.
+		 */
+		void drawWireDisc(const Vector3& position, const Vector3& normal, float radius);
+
+		/**
+		 * Draws a wireframe arc.
+		 *
+		 * @param[in]	position	Center of the arc.
+		 * @param[in]	normal		Orientation of the arc, pointing in the direction the arc is visible in.
+		 * @param[in]	radius		Radius of the arc.
+		 * @param[in]	startAngle	Angle at which to start the arc.
+		 * @param[in]	amountAngle	Length of the arc.
+		 */
+		void drawWireArc(const Vector3& position, const Vector3& normal, float radius, Degree startAngle, Degree amountAngle);
+
+		/** 
+		 * Draws a wireframe mesh.
+		 *
+		 * @param[in]	meshData	Object containing mesh vertices and indices. Vertices must be Vertex3 and indices 
+		 *							32-bit.
+		 */
+		void drawWireMesh(const SPtr<MeshData>& meshData);
+
+		/**
+		 * Draws a wireframe frustum.
+		 *
+		 * @param[in]	position	Origin of the frustum, or the eye point.
+		 * @param[in]	aspect		Ratio of frustum width over frustum height.
+		 * @param[in]	FOV			Horizontal field of view in degrees.
+		 * @param[in]	near		Distance to the near frustum plane.
+		 * @param[in]	far			Distance to the far frustum plane.
+		 */
+		void drawFrustum(const Vector3& position, float aspect, Degree FOV, float near, float far);
+
+		/**
+		 * Clears any objects that are currently drawing. ALl objects must be re-queued.
+		 */
+		void clear();
+
+		/** Performs per-frame operations. */
+		void _update();
+
+	private:
+		friend class ct::DebugDrawRenderer;
+
+		/** Data about a mesh rendered by the draw manager. */
+		struct MeshRenderData
+		{
+			MeshRenderData(const SPtr<ct::MeshBase>& mesh, DebugDrawMaterial type)
+				:mesh(mesh), type(type)
+			{ }
+
+			SPtr<ct::MeshBase> mesh;
+			DebugDrawMaterial type;
+		};
+
+		/** Converts mesh data from DrawHelper into mesh data usable by the debug draw renderer. */
+		Vector<MeshRenderData> createMeshProxyData(const Vector<DrawHelper::ShapeMeshData>& meshData);
+
+		DrawHelper* mDrawHelper;
+		Vector<DrawHelper::ShapeMeshData> mActiveMeshes;
+
+		SPtr<ct::DebugDrawRenderer> mRenderer;
+	};
+
+	/** @} */
+
+	namespace ct
+	{
+	/** @addtogroup Utility-Engine-Internal
+	 *  @{
+	 */
+
+	BS_PARAM_BLOCK_BEGIN(DebugDrawParamsDef)
+		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatViewProj)
+		BS_PARAM_BLOCK_ENTRY(Vector4, gViewDir)
+	BS_PARAM_BLOCK_END
+
+	extern DebugDrawParamsDef gDebugDrawParamsDef;
+
+	/** Handles rendering of debug shapes. */
+	class DebugDrawMat : public RendererMaterial<DebugDrawMat>
+	{
+		RMAT_DEF("DebugDraw.bsl");
+
+	public:
+		DebugDrawMat();
+
+		/** Executes the material using the provided parameters. */
+		void execute(const SPtr<GpuParamBlockBuffer>& params, const SPtr<MeshBase>& mesh);
+
+		/** Returns the material variation matching the provided parameters. */
+		static DebugDrawMat* getVariation(DebugDrawMaterial drawMat);
+	private:
+		static ShaderVariation VAR_Solid;
+		static ShaderVariation VAR_Wire;
+		static ShaderVariation VAR_Line;
+	};
+
+	/** Performs rendering of meshes provided by DebugDraw. */
+	class DebugDrawRenderer : public RendererExtension
+	{
+		friend class DebugDraw;
+
+	public:
+		DebugDrawRenderer();
+
+	private:
+		/**	@copydoc RendererExtension::initialize */
+		void initialize(const Any& data) override;
+
+		/**	@copydoc RendererExtension::check */
+		bool check(const Camera& camera) override;
+
+		/**	@copydoc RendererExtension::render */
+		void render(const Camera& camera) override;
+
+		/**
+		 * Updates the internal data that is used for rendering. Normally you would call this after updating the meshes
+		 * on the sim thread.
+		 *
+		 * @param[in]	meshes			Meshes to render.
+		 */
+		void updateData(const Vector<DebugDraw::MeshRenderData>& meshes);
+
+		Vector<DebugDraw::MeshRenderData> mMeshes;
+		SPtr<GpuParamBlockBuffer> mParamBuffer;
+	};
+
+	/** @} */
+	}
+}

+ 2 - 2
Source/BansheeEngine/Include/BsDrawHelper.h

@@ -183,8 +183,8 @@ namespace bs
 			Vector3 position;
 			Vector3 position;
 			float aspect;
 			float aspect;
 			Degree FOV;
 			Degree FOV;
-			float near;
-			float far;
+			float nearDist;
+			float farDist;
 		};
 		};
 
 
 		struct ConeData : CommonData
 		struct ConeData : CommonData

+ 4 - 0
Source/BansheeEngine/Source/BsApplication.cpp

@@ -18,6 +18,7 @@
 #include "BsCoreObjectManager.h"
 #include "BsCoreObjectManager.h"
 #include "BsRendererManager.h"
 #include "BsRendererManager.h"
 #include "BsRendererMaterialManager.h"
 #include "BsRendererMaterialManager.h"
+#include "BsDebugDraw.h"
 #include "BsPlatform.h"
 #include "BsPlatform.h"
 #include "BsEngineShaderIncludeHandler.h"
 #include "BsEngineShaderIncludeHandler.h"
 #include "BsEngineConfig.h"
 #include "BsEngineConfig.h"
@@ -67,6 +68,7 @@ namespace bs
 		Platform::setIcon(BuiltinResources::instance().getBansheeIcon());
 		Platform::setIcon(BuiltinResources::instance().getBansheeIcon());
 
 
 		SceneManager::instance().setMainRenderTarget(getPrimaryWindow());
 		SceneManager::instance().setMainRenderTarget(getPrimaryWindow());
+		DebugDraw::startUp();
 
 
 		ScriptManager::startUp();
 		ScriptManager::startUp();
 
 
@@ -81,6 +83,7 @@ namespace bs
 		SceneManager::instance().clearScene(true);
 		SceneManager::instance().clearScene(true);
 
 
 		ScriptManager::shutDown();
 		ScriptManager::shutDown();
+		DebugDraw::shutDown();
 
 
 		if (mStartUpDesc.scripting)
 		if (mStartUpDesc.scripting)
 			unloadScriptSystem();
 			unloadScriptSystem();
@@ -100,6 +103,7 @@ namespace bs
 		CoreApplication::postUpdate();
 		CoreApplication::postUpdate();
 
 
 		PROFILE_CALL(GUIManager::instance().update(), "GUI");
 		PROFILE_CALL(GUIManager::instance().update(), "GUI");
+		DebugDraw::instance()._update();
 	}
 	}
 
 
 	void Application::loadScriptSystem()
 	void Application::loadScriptSystem()

+ 243 - 0
Source/BansheeEngine/Source/BsDebugDraw.cpp

@@ -0,0 +1,243 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsDebugDraw.h"
+#include "BsMesh.h"
+#include "BsVertexDataDesc.h"
+#include "BsShapeMeshes3D.h"
+#include "BsMeshHeap.h"
+#include "BsSpriteTexture.h"
+#include "BsCoreThread.h"
+#include "BsMaterial.h"
+#include "BsGpuParams.h"
+#include "BsGpuParamsSet.h"
+#include "BsRenderAPI.h"
+#include "BsRenderer.h"
+#include "BsRendererUtility.h"
+#include "BsTransientMesh.h"
+#include "BsDrawHelper.h"
+#include "BsRendererExtension.h"
+#include "BsBuiltinResources.h"
+#include "BsCamera.h"
+
+using namespace std::placeholders;
+
+namespace bs
+{
+	DebugDraw::DebugDraw()
+		: mDrawHelper(nullptr)
+	{
+		mDrawHelper = bs_new<DrawHelper>();
+		mRenderer = RendererExtension::create<ct::DebugDrawRenderer>(nullptr);
+	}
+
+	DebugDraw::~DebugDraw()
+	{
+		mDrawHelper->clearMeshes(mActiveMeshes);
+		mActiveMeshes.clear();
+
+		bs_delete(mDrawHelper);
+	}
+
+	void DebugDraw::setColor(const Color& color)
+	{
+		mDrawHelper->setColor(color);
+	}
+
+	void DebugDraw::setTransform(const Matrix4& transform)
+	{
+		mDrawHelper->setTransform(transform);
+	}
+
+	void DebugDraw::drawCube(const Vector3& position, const Vector3& extents)
+	{
+		mDrawHelper->cube(position, extents);
+	}
+
+	void DebugDraw::drawSphere(const Vector3& position, float radius)
+	{
+		mDrawHelper->sphere(position, radius);
+	}
+
+	void DebugDraw::drawCone(const Vector3& base, const Vector3& normal, float height, float radius, const Vector2& scale)
+	{
+		mDrawHelper->cone(base, normal, height, radius, scale);
+	}
+
+	void DebugDraw::drawDisc(const Vector3& position, const Vector3& normal, float radius)
+	{
+		mDrawHelper->disc(position, normal, radius);
+	}
+
+	void DebugDraw::drawWireCube(const Vector3& position, const Vector3& extents)
+	{
+		mDrawHelper->wireCube(position, extents);
+	}
+
+	void DebugDraw::drawWireSphere(const Vector3& position, float radius)
+	{
+		mDrawHelper->wireSphere(position, radius);
+	}
+
+	void DebugDraw::drawWireCone(const Vector3& base, const Vector3& normal, float height, float radius, const Vector2& scale)
+	{
+		mDrawHelper->wireCone(base, normal, height, radius, scale);
+	}
+
+	void DebugDraw::drawLine(const Vector3& start, const Vector3& end)
+	{
+		mDrawHelper->line(start, end);
+	}
+
+	void DebugDraw::drawLineList(const Vector<Vector3>& linePoints)
+	{
+		mDrawHelper->lineList(linePoints);
+	}
+
+	void DebugDraw::drawWireDisc(const Vector3& position, const Vector3& normal, float radius)
+	{
+		mDrawHelper->wireDisc(position, normal, radius);
+	}
+
+	void DebugDraw::drawWireArc(const Vector3& position, const Vector3& normal, float radius, 
+		Degree startAngle, Degree amountAngle)
+	{
+		mDrawHelper->wireArc(position, normal, radius, startAngle, amountAngle);
+	}
+
+	void DebugDraw::drawWireMesh(const SPtr<MeshData>& meshData)
+	{
+		mDrawHelper->wireMesh(meshData);
+	}
+
+	void DebugDraw::drawFrustum(const Vector3& position, float aspect, Degree FOV, float near, float far)
+	{
+		mDrawHelper->frustum(position, aspect, FOV, near, far);
+	}
+
+	Vector<DebugDraw::MeshRenderData> DebugDraw::createMeshProxyData(const Vector<DrawHelper::ShapeMeshData>& meshData)
+	{
+		Vector<MeshRenderData> proxyData;
+		for (auto& entry : meshData)
+		{
+			if (entry.type == DrawHelper::MeshType::Solid)
+				proxyData.push_back(MeshRenderData(entry.mesh->getCore(), DebugDrawMaterial::Solid));
+			else if (entry.type == DrawHelper::MeshType::Wire)
+				proxyData.push_back(MeshRenderData(entry.mesh->getCore(), DebugDrawMaterial::Wire));
+			else if (entry.type == DrawHelper::MeshType::Line)
+				proxyData.push_back(MeshRenderData(entry.mesh->getCore(), DebugDrawMaterial::Line));
+		}
+
+		return proxyData;
+	}
+
+	void DebugDraw::clear()
+	{
+		mDrawHelper->clear();
+	}
+
+	void DebugDraw::_update()
+	{
+		mDrawHelper->clearMeshes(mActiveMeshes);
+		mActiveMeshes.clear();
+
+		mDrawHelper->buildMeshes(DrawHelper::SortType::None, Vector3::ZERO);
+		mActiveMeshes = mDrawHelper->getMeshes();
+
+		Vector<MeshRenderData> proxyData = createMeshProxyData(mActiveMeshes);
+
+		ct::DebugDrawRenderer* renderer = mRenderer.get();
+		gCoreThread().queueCommand(std::bind(&ct::DebugDrawRenderer::updateData, renderer, proxyData));
+	}
+
+	namespace ct
+	{
+
+	DebugDrawParamsDef gDebugDrawParamsDef;
+
+	ShaderVariation DebugDrawMat::VAR_Solid = ShaderVariation({
+		ShaderVariation::Param("SOLID", true)
+	});
+
+	ShaderVariation DebugDrawMat::VAR_Line = ShaderVariation({
+		ShaderVariation::Param("LINE", true)
+	});
+
+	ShaderVariation DebugDrawMat::VAR_Wire = ShaderVariation({
+		ShaderVariation::Param("WIRE", true)
+	});
+
+	DebugDrawMat::DebugDrawMat()
+	{
+		// Do nothing
+	}
+
+	void DebugDrawMat::_initVariations(ShaderVariations& variations)
+	{
+		variations.add(VAR_Solid);
+		variations.add(VAR_Line);
+		variations.add(VAR_Wire);
+	}
+
+	void DebugDrawMat::execute(const SPtr<GpuParamBlockBuffer>& params, const SPtr<MeshBase>& mesh)
+	{
+		mParamsSet->setParamBlockBuffer("Params", params);
+
+		gRendererUtility().setPass(mMaterial);
+		gRendererUtility().setPassParams(mParamsSet);
+		gRendererUtility().draw(mesh);
+	}
+
+	DebugDrawMat* DebugDrawMat::getVariation(DebugDrawMaterial mat)
+	{
+		if (mat == DebugDrawMaterial::Solid)
+			return get(VAR_Solid);
+		
+		if (mat == DebugDrawMaterial::Wire)
+			return get(VAR_Wire);
+
+		return get(VAR_Line);
+	}
+
+	DebugDrawRenderer::DebugDrawRenderer()
+		:RendererExtension(RenderLocation::PostLightPass, 0)
+	{
+	}
+
+	void DebugDrawRenderer::initialize(const Any& data)
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		mParamBuffer = gDebugDrawParamsDef.createBuffer();
+	}
+
+	void DebugDrawRenderer::updateData(const Vector<DebugDraw::MeshRenderData>& meshes)
+	{
+		mMeshes = meshes;
+	}
+
+	bool DebugDrawRenderer::check(const Camera& camera)
+	{
+		return true;
+	}
+
+	void DebugDrawRenderer::render(const Camera& camera)
+	{
+		SPtr<RenderTarget> renderTarget = camera.getViewport()->getTarget();
+		if (renderTarget == nullptr)
+			return;
+
+		Matrix4 viewMatrix = camera.getViewMatrix();
+		Matrix4 projMatrix = camera.getProjectionMatrixRS();
+		Matrix4 viewProjMat = projMatrix * viewMatrix;
+
+		gDebugDrawParamsDef.gMatViewProj.set(mParamBuffer, viewProjMat);
+		gDebugDrawParamsDef.gViewDir.set(mParamBuffer, (Vector4)camera.getForward());
+
+		for (auto& entry : mMeshes)
+		{
+			DebugDrawMat* mat = DebugDrawMat::getVariation(entry.type);
+			mat->execute(mParamBuffer, entry.mesh);
+		}
+	}
+	}
+}

+ 4 - 4
Source/BansheeEngine/Source/BsDrawHelper.cpp

@@ -159,8 +159,8 @@ namespace bs
 		frustumData.position = position;
 		frustumData.position = position;
 		frustumData.aspect = aspect;
 		frustumData.aspect = aspect;
 		frustumData.FOV = FOV;
 		frustumData.FOV = FOV;
-		frustumData.near = near;
-		frustumData.far = far;
+		frustumData.nearDist = near;
+		frustumData.farDist = far;
 		frustumData.color = mColor;
 		frustumData.color = mColor;
 		frustumData.transform = mTransform;
 		frustumData.transform = mTransform;
 		frustumData.layer = mLayer;
 		frustumData.layer = mLayer;
@@ -1065,8 +1065,8 @@ namespace bs
 					{
 					{
 						FrustumData& frustumData = mFrustumData[shapeData.idx];
 						FrustumData& frustumData = mFrustumData[shapeData.idx];
 
 
-						ShapeMeshes3D::wireFrustum(frustumData.position, frustumData.aspect, frustumData.FOV, frustumData.near,
-							frustumData.far, meshData, curVertexOffset, curIndexOffet);
+						ShapeMeshes3D::wireFrustum(frustumData.position, frustumData.aspect, frustumData.FOV, frustumData.nearDist,
+							frustumData.farDist, meshData, curVertexOffset, curIndexOffet);
 
 
 						transform = &frustumData.transform;
 						transform = &frustumData.transform;
 						color = frustumData.color.getAsRGBA();
 						color = frustumData.color.getAsRGBA();

+ 2 - 0
Source/RenderBeast/Include/BsImageBasedLighting.h

@@ -101,6 +101,7 @@ namespace bs { namespace ct
 		void populate(const SPtr<GpuParamsSet>& paramsSet, GpuProgramType programType, bool optional, bool gridIndices);
 		void populate(const SPtr<GpuParamsSet>& paramsSet, GpuProgramType programType, bool optional, bool gridIndices);
 
 
 		GpuParamTexture skyReflectionsTexParam;
 		GpuParamTexture skyReflectionsTexParam;
+		GpuParamTexture ambientOcclusionTexParam;
 		GpuParamTexture reflectionProbeCubemapsTexParam;
 		GpuParamTexture reflectionProbeCubemapsTexParam;
 
 
 		GpuParamTexture preintegratedEnvBRDFParam;
 		GpuParamTexture preintegratedEnvBRDFParam;
@@ -136,6 +137,7 @@ namespace bs { namespace ct
 			SPtr<Texture> sceneColorTex;
 			SPtr<Texture> sceneColorTex;
 			SPtr<GpuBuffer> sceneColorBuffer;
 			SPtr<GpuBuffer> sceneColorBuffer;
 			SPtr<Texture> preIntegratedGF;
 			SPtr<Texture> preIntegratedGF;
+			SPtr<Texture> ambientOcclusion;
 		};
 		};
 
 
 		TiledDeferredImageBasedLightingMat();
 		TiledDeferredImageBasedLightingMat();

+ 4 - 1
Source/RenderBeast/Include/BsLightProbes.h

@@ -84,11 +84,13 @@ namespace bs { namespace ct
 		 * @param[in]	lightProbesInfo		Information about light probes.
 		 * @param[in]	lightProbesInfo		Information about light probes.
 		 * @param[in]	skybox				Skybox, if available. If sky is not available, but sky rendering is enabled, 
 		 * @param[in]	skybox				Skybox, if available. If sky is not available, but sky rendering is enabled, 
 		 *									the system will instead use a default irradiance texture.
 		 *									the system will instead use a default irradiance texture.
+		 * @param[in]	ambientOcclusion	Texture containing per-pixel ambient occlusion.
 		 * @param[in]	output				Output texture to write the radiance to. The evaluated value will be added to 
 		 * @param[in]	output				Output texture to write the radiance to. The evaluated value will be added to 
 		 *									existing radiance in the texture, using blending.
 		 *									existing radiance in the texture, using blending.
 		 */
 		 */
 		void execute(const RendererView& view, const GBufferTextures& gbuffer, const SPtr<Texture>& lightProbeIndices,
 		void execute(const RendererView& view, const GBufferTextures& gbuffer, const SPtr<Texture>& lightProbeIndices,
-			const LightProbesInfo& lightProbesInfo, const Skybox* skybox, const SPtr<RenderTexture>& output);
+			const LightProbesInfo& lightProbesInfo, const Skybox* skybox, const SPtr<Texture>& ambientOcclusion,
+			const SPtr<RenderTexture>& output);
 
 
 		/** 
 		/** 
 		 * Returns the material variation matching the provided parameters. 
 		 * Returns the material variation matching the provided parameters. 
@@ -103,6 +105,7 @@ namespace bs { namespace ct
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		SPtr<GpuParamBlockBuffer> mParamBuffer;
 		GpuParamTexture mParamInputTex;
 		GpuParamTexture mParamInputTex;
 		GpuParamTexture mParamSkyIrradianceTex;
 		GpuParamTexture mParamSkyIrradianceTex;
+		GpuParamTexture mParamAmbientOcclusionTex;
 		GpuParamBuffer mParamSHCoeffsBuffer;
 		GpuParamBuffer mParamSHCoeffsBuffer;
 		GpuParamBuffer mParamTetrahedraBuffer;
 		GpuParamBuffer mParamTetrahedraBuffer;
 		GpuParamBuffer mParamTetFacesBuffer;
 		GpuParamBuffer mParamTetFacesBuffer;

+ 4 - 0
Source/RenderBeast/Source/BsImageBasedLighting.cpp

@@ -120,6 +120,9 @@ namespace bs { namespace ct
 			params->getTextureParam(programType, "gPreintegratedEnvBRDF", preintegratedEnvBRDFParam);
 			params->getTextureParam(programType, "gPreintegratedEnvBRDF", preintegratedEnvBRDFParam);
 		}
 		}
 
 
+		// AO
+		params->getTextureParam(programType, "gAmbientOcclusionTex", ambientOcclusionTexParam);
+
 		if(gridIndices)
 		if(gridIndices)
 		{
 		{
 			if (!optional || params->hasBuffer(programType, "gReflectionProbeIndices"))
 			if (!optional || params->hasBuffer(programType, "gReflectionProbeIndices"))
@@ -258,6 +261,7 @@ namespace bs { namespace ct
 		mImageBasedParams.reflectionProbesParam.set(probeData.getProbeBuffer());
 		mImageBasedParams.reflectionProbesParam.set(probeData.getProbeBuffer());
 		mImageBasedParams.reflectionProbeCubemapsTexParam.set(sceneInfo.reflProbeCubemapsTex);
 		mImageBasedParams.reflectionProbeCubemapsTexParam.set(sceneInfo.reflProbeCubemapsTex);
 		mImageBasedParams.skyReflectionsTexParam.set(skyFilteredRadiance);
 		mImageBasedParams.skyReflectionsTexParam.set(skyFilteredRadiance);
+		mImageBasedParams.ambientOcclusionTexParam.set(inputs.ambientOcclusion);
 
 
 		mParamsSet->setParamBlockBuffer("PerCamera", view.getPerViewBuffer(), true);
 		mParamsSet->setParamBlockBuffer("PerCamera", view.getPerViewBuffer(), true);
 
 

+ 3 - 1
Source/RenderBeast/Source/BsLightProbes.cpp

@@ -112,6 +112,7 @@ namespace bs { namespace ct
 
 
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 		SPtr<GpuParams> params = mParamsSet->getGpuParams();
 		params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gSkyIrradianceTex", mParamSkyIrradianceTex);
 		params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gSkyIrradianceTex", mParamSkyIrradianceTex);
+		params->getTextureParam(GPT_FRAGMENT_PROGRAM, "gAmbientOcclusionTex", mParamAmbientOcclusionTex);
 
 
 		if(!mSkyOnly)
 		if(!mSkyOnly)
 		{
 		{
@@ -135,7 +136,7 @@ namespace bs { namespace ct
 
 
 	void IrradianceEvaluateMat::execute(const RendererView& view, const GBufferTextures& gbuffer, 
 	void IrradianceEvaluateMat::execute(const RendererView& view, const GBufferTextures& gbuffer, 
 		const SPtr<Texture>& lightProbeIndices, const LightProbesInfo& lightProbesInfo, const Skybox* skybox, 
 		const SPtr<Texture>& lightProbeIndices, const LightProbesInfo& lightProbesInfo, const Skybox* skybox, 
-		const SPtr<RenderTexture>& output)
+		const SPtr<Texture>& ambientOcclusion, const SPtr<RenderTexture>& output)
 	{
 	{
 		const RendererViewProperties& viewProps = view.getProperties();
 		const RendererViewProperties& viewProps = view.getProperties();
 
 
@@ -153,6 +154,7 @@ namespace bs { namespace ct
 			skyIrradiance = RendererTextures::defaultIndirect;
 			skyIrradiance = RendererTextures::defaultIndirect;
 
 
 		mParamSkyIrradianceTex.set(skyIrradiance);
 		mParamSkyIrradianceTex.set(skyIrradiance);
+		mParamAmbientOcclusionTex.set(ambientOcclusion);
 
 
 		if(!mSkyOnly)
 		if(!mSkyOnly)
 		{
 		{

+ 27 - 1
Source/RenderBeast/Source/BsRenderCompositor.cpp

@@ -657,6 +657,15 @@ namespace bs { namespace ct
 		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[1]);
 		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[1]);
 		RCNodeLightAccumulation* lightAccumNode = static_cast <RCNodeLightAccumulation*>(inputs.inputNodes[2]);
 		RCNodeLightAccumulation* lightAccumNode = static_cast <RCNodeLightAccumulation*>(inputs.inputNodes[2]);
 
 
+		SPtr<Texture> ssao;
+		if (inputs.view.getRenderSettings().ambientOcclusion.enabled)
+		{
+			RCNodeSSAO* ssaoNode = static_cast<RCNodeSSAO*>(inputs.inputNodes[4]);
+			ssao = ssaoNode->output->texture;
+		}
+		else
+			ssao = Texture::WHITE;
+
 		GpuResourcePool& resPool = GpuResourcePool::instance();
 		GpuResourcePool& resPool = GpuResourcePool::instance();
 		const RendererViewProperties& viewProps = inputs.view.getProperties();
 		const RendererViewProperties& viewProps = inputs.view.getProperties();
 
 
@@ -708,7 +717,7 @@ namespace bs { namespace ct
 		if (volumeIndices)
 		if (volumeIndices)
 			volumeIndicesTex = volumeIndices->texture;
 			volumeIndicesTex = volumeIndices->texture;
 
 
-		evaluateMat->execute(inputs.view, gbuffer, volumeIndicesTex, lpInfo, inputs.scene.skybox, 
+		evaluateMat->execute(inputs.view, gbuffer, volumeIndicesTex, lpInfo, inputs.scene.skybox, ssao, 
 			lightAccumNode->renderTarget);
 			lightAccumNode->renderTarget);
 
 
 		if(volumeIndices)
 		if(volumeIndices)
@@ -729,6 +738,9 @@ namespace bs { namespace ct
 		deps.push_back(RCNodeLightAccumulation::getNodeId());
 		deps.push_back(RCNodeLightAccumulation::getNodeId());
 		deps.push_back(RCNodeStandardDeferredLighting::getNodeId());
 		deps.push_back(RCNodeStandardDeferredLighting::getNodeId());
 
 
+		if(view.getRenderSettings().ambientOcclusion.enabled)
+			deps.push_back(RCNodeSSAO::getNodeId());
+
 		if (view.getProperties().numSamples > 1)
 		if (view.getProperties().numSamples > 1)
 			deps.push_back(RCNodeUnflattenLightAccum::getNodeId());
 			deps.push_back(RCNodeUnflattenLightAccum::getNodeId());
 
 
@@ -742,6 +754,15 @@ namespace bs { namespace ct
 		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[2]);
 		RCNodeSceneDepth* sceneDepthNode = static_cast<RCNodeSceneDepth*>(inputs.inputNodes[2]);
 		RCNodeLightAccumulation* lightAccumNode = static_cast <RCNodeLightAccumulation*>(inputs.inputNodes[3]);
 		RCNodeLightAccumulation* lightAccumNode = static_cast <RCNodeLightAccumulation*>(inputs.inputNodes[3]);
 
 
+		SPtr<Texture> ssao;
+		if (inputs.view.getRenderSettings().ambientOcclusion.enabled)
+		{
+			RCNodeSSAO* ssaoNode = static_cast<RCNodeSSAO*>(inputs.inputNodes[5]);
+			ssao = ssaoNode->output->texture;
+		}
+		else
+			ssao = Texture::WHITE;
+
 		const RendererViewProperties& viewProps = inputs.view.getProperties();
 		const RendererViewProperties& viewProps = inputs.view.getProperties();
 		TiledDeferredImageBasedLightingMat* material = TiledDeferredImageBasedLightingMat::getVariation(viewProps.numSamples);
 		TiledDeferredImageBasedLightingMat* material = TiledDeferredImageBasedLightingMat::getVariation(viewProps.numSamples);
 
 
@@ -753,6 +774,7 @@ namespace bs { namespace ct
 		iblInputs.sceneColorTex = sceneColorNode->sceneColorTex->texture;
 		iblInputs.sceneColorTex = sceneColorNode->sceneColorTex->texture;
 		iblInputs.lightAccumulation = lightAccumNode->lightAccumulationTex->texture;
 		iblInputs.lightAccumulation = lightAccumNode->lightAccumulationTex->texture;
 		iblInputs.preIntegratedGF = RendererTextures::preintegratedEnvGF;
 		iblInputs.preIntegratedGF = RendererTextures::preintegratedEnvGF;
+		iblInputs.ambientOcclusion = ssao;
 
 
 		if(sceneColorNode->flattenedSceneColorBuffer)
 		if(sceneColorNode->flattenedSceneColorBuffer)
 			iblInputs.sceneColorBuffer = sceneColorNode->flattenedSceneColorBuffer->buffer;
 			iblInputs.sceneColorBuffer = sceneColorNode->flattenedSceneColorBuffer->buffer;
@@ -775,6 +797,9 @@ namespace bs { namespace ct
 		deps.push_back(RCNodeLightAccumulation::getNodeId());
 		deps.push_back(RCNodeLightAccumulation::getNodeId());
 		deps.push_back(RCNodeIndirectLighting::getNodeId());
 		deps.push_back(RCNodeIndirectLighting::getNodeId());
 
 
+		if(view.getRenderSettings().ambientOcclusion.enabled)
+			deps.push_back(RCNodeSSAO::getNodeId());
+
 		return deps;
 		return deps;
 	}
 	}
 
 
@@ -859,6 +884,7 @@ namespace bs { namespace ct
 				iblParams.reflectionProbesParam.set(visibleReflProbeData.getProbeBuffer());
 				iblParams.reflectionProbesParam.set(visibleReflProbeData.getProbeBuffer());
 
 
 				iblParams.skyReflectionsTexParam.set(skyFilteredRadiance);
 				iblParams.skyReflectionsTexParam.set(skyFilteredRadiance);
+				iblParams.ambientOcclusionTexParam.set(Texture::WHITE); // Note: Add SSAO here?
 
 
 				iblParams.reflectionProbeCubemapsTexParam.set(sceneInfo.reflProbeCubemapsTex);
 				iblParams.reflectionProbeCubemapsTexParam.set(sceneInfo.reflProbeCubemapsTex);
 				iblParams.preintegratedEnvBRDFParam.set(RendererTextures::preintegratedEnvGF);
 				iblParams.preintegratedEnvBRDFParam.set(RendererTextures::preintegratedEnvGF);