Procházet zdrojové kódy

Refactoring renderer so its render() method can easily be called manually

BearishSun před 9 roky
rodič
revize
bb40943c63

+ 8 - 5
Source/RenderBeast/Include/BsPostProcessing.h

@@ -223,7 +223,7 @@ namespace bs { namespace ct
 		TonemappingMat();
 		TonemappingMat();
 
 
 		/** Executes the post-process effect with the provided parameters. */
 		/** Executes the post-process effect with the provided parameters. */
-		void execute(const SPtr<RenderTexture>& sceneColor, const SPtr<Viewport>& outputViewport,
+		void execute(const SPtr<RenderTexture>& sceneColor, const SPtr<RenderTarget>& outputRT, const Rect2& outputRect,
 			PostProcessInfo& ppInfo);
 			PostProcessInfo& ppInfo);
 
 
 	private:
 	private:
@@ -242,9 +242,12 @@ namespace bs { namespace ct
 	class BS_BSRND_EXPORT PostProcessing : public Module<PostProcessing>
 	class BS_BSRND_EXPORT PostProcessing : public Module<PostProcessing>
 	{
 	{
 	public:
 	public:
-		/** Renders post-processing effects for the provided render target. */
-		void postProcess(const SPtr<RenderTexture>& sceneColor, const Camera* camera,
-			PostProcessInfo& ppInfo, float frameDelta);
+		/** 
+		 * Renders post-processing effects for the provided render target. Resolves provided scene color texture into the
+		 * view's final output render target. Once the method exits, final render target is guaranteed to be currently
+		 * bound for rendering. 
+		 */
+		void postProcess(RendererCamera* viewInfo, const SPtr<RenderTexture>& sceneColor, float frameDelta);
 		
 		
 	private:
 	private:
 		DownsampleMat mDownsample;
 		DownsampleMat mDownsample;
@@ -260,4 +263,4 @@ namespace bs { namespace ct
 	};
 	};
 
 
 	/** @} */
 	/** @} */
-}}
+}}

+ 5 - 24
Source/RenderBeast/Include/BsRenderBeast.h

@@ -37,15 +37,6 @@ namespace bs
 	 */
 	 */
 	class RenderBeast : public Renderer
 	class RenderBeast : public Renderer
 	{
 	{
-		/** Renderer information specific to a single frame. */
-		struct RendererFrame
-		{
-			RendererFrame(float delta, const RendererAnimationData& animData);
-
-			float delta;
-			const RendererAnimationData& animData;
-		};
-
 		/**	Renderer information specific to a single render target. */
 		/**	Renderer information specific to a single render target. */
 		struct RendererRenderTarget
 		struct RendererRenderTarget
 		{
 		{
@@ -147,26 +138,18 @@ namespace bs
 		void renderAllCore(float time, float delta);
 		void renderAllCore(float time, float delta);
 
 
 		/**
 		/**
-		 * Renders all objects visible by the provided camera.
-		 *
-		 * @param[in]	frameInfo	Renderer information specific to this frame.
-		 * @param[in]	rtInfo		Render target information containing the camera to render.
-		 * @param[in]	camIdx		Index of the camera to render.
-		 * 					
+		 * Renders all objects visible by the provided view.
+		 *			
 		 * @note	Core thread only.
 		 * @note	Core thread only.
 		 */
 		 */
-		void render(const RendererFrame& frameInfo, RendererRenderTarget& rtInfo, UINT32 camIdx);
+		void render(RendererCamera* viewInfo, float frameDelta);
 
 
 		/**
 		/**
 		 * Renders all overlay callbacks attached to the provided camera.
 		 * Renders all overlay callbacks attached to the provided camera.
-		 *
-		 * @param[in]	frameInfo	Renderer information specific to this frame.
-		 * @param[in]	rtInfo		Render target information containing the camera to render.
-		 * @param[in]	camIdx		Index of the camera to render.
 		 * 					
 		 * 					
 		 * @note	Core thread only.
 		 * @note	Core thread only.
 		 */
 		 */
-		void renderOverlay(const RendererFrame& frameInfo, RendererRenderTarget& rtInfo, UINT32 camIdx);
+		void renderOverlay(const Camera* camera, bool clear);
 
 
 		/** 
 		/** 
 		 * Renders a single element of a renderable object. 
 		 * Renders a single element of a renderable object. 
@@ -175,11 +158,9 @@ namespace bs
 		 * @param[in]	passIdx		Index of the material pass to render the element with.
 		 * @param[in]	passIdx		Index of the material pass to render the element with.
 		 * @param[in]	bindPass	If true the material pass will be bound for rendering, if false it is assumed it is
 		 * @param[in]	bindPass	If true the material pass will be bound for rendering, if false it is assumed it is
 		 *							already bound.
 		 *							already bound.
-		 * @param[in]	frameInfo	Renderer information specific to this frame.
 		 * @param[in]	viewProj	View projection matrix of the camera the element is being rendered with.
 		 * @param[in]	viewProj	View projection matrix of the camera the element is being rendered with.
 		 */
 		 */
-		void renderElement(const BeastRenderableElement& element, UINT32 passIdx, bool bindPass, 
-			const RendererFrame& frameInfo, const Matrix4& viewProj);
+		void renderElement(const BeastRenderableElement& element, UINT32 passIdx, bool bindPass, const Matrix4& viewProj);
 
 
 		/**	Creates data used by the renderer on the core thread. */
 		/**	Creates data used by the renderer on the core thread. */
 		void initializeCore();
 		void initializeCore();

+ 1 - 0
Source/RenderBeast/Include/BsRenderBeastPrerequisites.h

@@ -36,4 +36,5 @@ namespace bs { namespace ct
 	struct RenderBeastOptions;
 	struct RenderBeastOptions;
 	struct PooledRenderTexture;
 	struct PooledRenderTexture;
 	class RenderTargets;
 	class RenderTargets;
+	class RendererCamera;
 }}
 }}

+ 36 - 0
Source/RenderBeast/Include/BsRendererCamera.h

@@ -51,7 +51,10 @@ namespace bs { namespace ct
 	/** Set of properties describing the output render target used by a renderer view. */
 	/** Set of properties describing the output render target used by a renderer view. */
 	struct RENDERER_VIEW_TARGET_DESC
 	struct RENDERER_VIEW_TARGET_DESC
 	{
 	{
+		SPtr<RenderTarget> target;
+
 		Rect2I viewRect;
 		Rect2I viewRect;
+		Rect2 nrmViewRect;
 		UINT32 targetWidth;
 		UINT32 targetWidth;
 		UINT32 targetHeight;
 		UINT32 targetHeight;
 		UINT32 numSamples;
 		UINT32 numSamples;
@@ -75,12 +78,15 @@ namespace bs { namespace ct
 
 
 		bool isOverlay : 1;
 		bool isOverlay : 1;
 		bool isHDR : 1;
 		bool isHDR : 1;
+		bool triggerCallbacks : 1;
+		bool runPostProcessing : 1;
 
 
 		UINT64 visibleLayers;
 		UINT64 visibleLayers;
 		ConvexVolume cullFrustum;
 		ConvexVolume cullFrustum;
 
 
 		StateReduction stateReduction;
 		StateReduction stateReduction;
 
 
+		const Camera* sceneCamera;
 		SPtr<Texture> skyboxTexture;
 		SPtr<Texture> skyboxTexture;
 	};
 	};
 
 
@@ -104,6 +110,36 @@ namespace bs { namespace ct
 		/** Updates all internal information with new view information. */
 		/** Updates all internal information with new view information. */
 		void setView(const RENDERER_VIEW_DESC& desc);
 		void setView(const RENDERER_VIEW_DESC& desc);
 
 
+		/** Returns the world position of the view. */
+		Vector3 getViewOrigin() const { return mViewDesc.viewOrigin; }
+
+		/** Returns a matrix that contains combined projection and view transforms. */
+		Matrix4 getViewProjMatrix() const { return mViewDesc.projTransform * mViewDesc.viewTransform; }
+
+		/** Returns the distance to the near clipping plane. */
+		float getNearPlane() const { return mViewDesc.nearPlane; }
+
+		/** Returns true if the view requires high dynamic range rendering. */
+		bool isHDR() const { return mViewDesc.isHDR; }
+
+		/** Returns the texture to use for the skybox (if any). */
+		SPtr<Texture> getSkybox() const { return mViewDesc.skyboxTexture; }
+
+		/** Returns the final render target the rendered contents should be output to. */
+		SPtr<RenderTarget> getFinalTarget() const { return mViewDesc.target.target; }
+
+		/** Returns normalized coordinates of the viewport area this view renders to. */
+		Rect2 getViewportRect() const { return mViewDesc.target.nrmViewRect; }
+
+		/** Returns the scene camera this object is based of. This can be null for manually constructed renderer cameras. */
+		const Camera* getSceneCamera() const { return mViewDesc.sceneCamera; }
+
+		/** Returns true if external render callbacks should trigger for this view. */
+		bool checkTriggerCallbacks() const { return mViewDesc.triggerCallbacks; }
+
+		/** Returns true if post-processing effects should be triggered for this view. */
+		bool checkRunPostProcessing() const { return mViewDesc.runPostProcessing; }
+
 		/** 
 		/** 
 		 * Prepares render targets for rendering. When done call endRendering().
 		 * Prepares render targets for rendering. When done call endRendering().
 		 *
 		 *

+ 15 - 15
Source/RenderBeast/Source/BsPostProcessing.cpp

@@ -7,6 +7,7 @@
 #include "BsTextureManager.h"
 #include "BsTextureManager.h"
 #include "BsCamera.h"
 #include "BsCamera.h"
 #include "BsGpuParamsSet.h"
 #include "BsGpuParamsSet.h"
+#include "BsRendererCamera.h"
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
@@ -391,8 +392,8 @@ namespace bs { namespace ct
 	}
 	}
 
 
 	template<bool GammaOnly, bool AutoExposure>
 	template<bool GammaOnly, bool AutoExposure>
-	void TonemappingMat<GammaOnly, AutoExposure>::execute(const SPtr<RenderTexture>& sceneColor, const SPtr<Viewport>& outputViewport,
-		PostProcessInfo& ppInfo)
+	void TonemappingMat<GammaOnly, AutoExposure>::execute(const SPtr<RenderTexture>& sceneColor, 
+		const SPtr<RenderTarget>& outputRT, const Rect2& outputRect, PostProcessInfo& ppInfo)
 	{
 	{
 		gTonemappingParamDef.gRawGamma.set(mParamBuffer, 1.0f / ppInfo.settings->gamma);
 		gTonemappingParamDef.gRawGamma.set(mParamBuffer, 1.0f / ppInfo.settings->gamma);
 		gTonemappingParamDef.gManualExposureScale.set(mParamBuffer, Math::pow(2.0f, ppInfo.settings->exposureScale));
 		gTonemappingParamDef.gManualExposureScale.set(mParamBuffer, Math::pow(2.0f, ppInfo.settings->exposureScale));
@@ -415,10 +416,9 @@ namespace bs { namespace ct
 
 
 		// Render
 		// Render
 		RenderAPI& rapi = RenderAPI::instance();
 		RenderAPI& rapi = RenderAPI::instance();
-		SPtr<RenderTarget> target = outputViewport->getTarget();
 
 
-		rapi.setRenderTarget(target);
-		rapi.setViewport(outputViewport->getNormArea());
+		rapi.setRenderTarget(outputRT);
+		rapi.setViewport(outputRect);
 
 
 		gRendererUtility().setPass(mMaterial);
 		gRendererUtility().setPass(mMaterial);
 		gRendererUtility().setPassParams(mParamsSet);
 		gRendererUtility().setPassParams(mParamsSet);
@@ -430,13 +430,15 @@ namespace bs { namespace ct
 	template class TonemappingMat<true, false>;
 	template class TonemappingMat<true, false>;
 	template class TonemappingMat<false, false>;
 	template class TonemappingMat<false, false>;
 
 
-	void PostProcessing::postProcess(const SPtr<RenderTexture>& sceneColor, const Camera* camera, 
-		PostProcessInfo& ppInfo, float frameDelta)
+	void PostProcessing::postProcess(RendererCamera* viewInfo, const SPtr<RenderTexture>& sceneColor, float frameDelta)
 	{
 	{
+		PostProcessInfo& ppInfo = viewInfo->getPPInfo();
 		const StandardPostProcessSettings& settings = *ppInfo.settings;
 		const StandardPostProcessSettings& settings = *ppInfo.settings;
 
 
-		SPtr<Viewport> outputViewport = camera->getViewport();
-		bool hdr = camera->getFlags().isSet(CameraFlag::HDR);
+		SPtr<RenderTarget> finalRT = viewInfo->getFinalTarget();
+		Rect2 viewportRect = viewInfo->getViewportRect();
+
+		bool hdr = viewInfo->isHDR();
 
 
 		if(hdr && settings.enableAutoExposure)
 		if(hdr && settings.enableAutoExposure)
 		{
 		{
@@ -457,21 +459,19 @@ namespace bs { namespace ct
 				mCreateLUT.execute(ppInfo);
 				mCreateLUT.execute(ppInfo);
 
 
 			if (settings.enableAutoExposure)
 			if (settings.enableAutoExposure)
-				mTonemapping_AE.execute(sceneColor, outputViewport, ppInfo);
+				mTonemapping_AE.execute(sceneColor, finalRT, viewportRect, ppInfo);
 			else
 			else
-				mTonemapping.execute(sceneColor, outputViewport, ppInfo);
+				mTonemapping.execute(sceneColor, finalRT, viewportRect, ppInfo);
 		}
 		}
 		else
 		else
 		{
 		{
 			if (hdr && settings.enableAutoExposure)
 			if (hdr && settings.enableAutoExposure)
-				mTonemapping_AE_GO.execute(sceneColor, outputViewport, ppInfo);
+				mTonemapping_AE_GO.execute(sceneColor, finalRT, viewportRect, ppInfo);
 			else
 			else
-				mTonemapping_GO.execute(sceneColor, outputViewport, ppInfo);
+				mTonemapping_GO.execute(sceneColor, finalRT, viewportRect, ppInfo);
 		}
 		}
 
 
 		if (ppInfo.settingDirty)
 		if (ppInfo.settingDirty)
 			ppInfo.settingDirty = false;
 			ppInfo.settingDirty = false;
-
-		// TODO - External code depends on the main RT being bound when this exits, make this clearer
 	}
 	}
 }}
 }}

+ 108 - 79
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -37,10 +37,6 @@ using namespace std::placeholders;
 
 
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
-	RenderBeast::RendererFrame::RendererFrame(float delta, const RendererAnimationData& animData)
-		:delta(delta), animData(animData)
-	{ }
-
 	RenderBeast::RenderBeast()
 	RenderBeast::RenderBeast()
 		: mDefaultMaterial(nullptr), mPointLightInMat(nullptr), mPointLightOutMat(nullptr), mDirLightMat(nullptr)
 		: mDefaultMaterial(nullptr), mPointLightInMat(nullptr), mPointLightOutMat(nullptr), mDirLightMat(nullptr)
 		, mSkyboxMat(nullptr), mObjectRenderer(nullptr), mOptions(bs_shared_ptr_new<RenderBeastOptions>())
 		, mSkyboxMat(nullptr), mObjectRenderer(nullptr), mOptions(bs_shared_ptr_new<RenderBeastOptions>())
@@ -450,17 +446,18 @@ namespace bs { namespace ct
 			viewDesc.target.clearDepthValue = viewport->getClearDepthValue();
 			viewDesc.target.clearDepthValue = viewport->getClearDepthValue();
 			viewDesc.target.clearStencilValue = viewport->getClearStencilValue();
 			viewDesc.target.clearStencilValue = viewport->getClearStencilValue();
 
 
+			viewDesc.target.target = viewport->getTarget();
+			viewDesc.target.nrmViewRect = viewport->getNormArea();
 			viewDesc.target.viewRect = Rect2I(
 			viewDesc.target.viewRect = Rect2I(
 				viewport->getX(),
 				viewport->getX(),
 				viewport->getY(),
 				viewport->getY(),
 				(UINT32)viewport->getWidth(),
 				(UINT32)viewport->getWidth(),
 				(UINT32)viewport->getHeight());
 				(UINT32)viewport->getHeight());
 
 
-			SPtr<RenderTarget> rt = viewport->getTarget();
-			if (rt != nullptr)
+			if (viewDesc.target.target != nullptr)
 			{
 			{
-				viewDesc.target.targetWidth = rt->getProperties().getWidth();
-				viewDesc.target.targetHeight = rt->getProperties().getHeight();
+				viewDesc.target.targetWidth = viewDesc.target.target->getProperties().getWidth();
+				viewDesc.target.targetHeight = viewDesc.target.target->getProperties().getHeight();
 			}
 			}
 			else
 			else
 			{
 			{
@@ -472,6 +469,8 @@ namespace bs { namespace ct
 
 
 			viewDesc.isOverlay = camera->getFlags().isSet(CameraFlag::Overlay);
 			viewDesc.isOverlay = camera->getFlags().isSet(CameraFlag::Overlay);
 			viewDesc.isHDR = camera->getFlags().isSet(CameraFlag::HDR);
 			viewDesc.isHDR = camera->getFlags().isSet(CameraFlag::HDR);
+			viewDesc.triggerCallbacks = true;
+			viewDesc.runPostProcessing = true;
 
 
 			viewDesc.cullFrustum = camera->getWorldFrustum();
 			viewDesc.cullFrustum = camera->getWorldFrustum();
 			viewDesc.visibleLayers = camera->getLayers();
 			viewDesc.visibleLayers = camera->getLayers();
@@ -484,6 +483,7 @@ namespace bs { namespace ct
 
 
 			viewDesc.stateReduction = mCoreOptions->stateReductionMode;
 			viewDesc.stateReduction = mCoreOptions->stateReductionMode;
 			viewDesc.skyboxTexture = camera->getSkybox();
 			viewDesc.skyboxTexture = camera->getSkybox();
+			viewDesc.sceneCamera = camera;
 
 
 			if (iterFind != mCameras.end())
 			if (iterFind != mCameras.end())
 			{
 			{
@@ -631,7 +631,6 @@ namespace bs { namespace ct
 		// Retrieve animation data
 		// Retrieve animation data
 		AnimationManager::instance().waitUntilComplete();
 		AnimationManager::instance().waitUntilComplete();
 		const RendererAnimationData& animData = AnimationManager::instance().getRendererData();
 		const RendererAnimationData& animData = AnimationManager::instance().getRendererData();
-		RendererFrame frameInfo(delta, animData);
 
 
 		// Update per-object, bone matrix and morph shape GPU buffers
 		// Update per-object, bone matrix and morph shape GPU buffers
 		UINT32 numRenderables = (UINT32)mRenderables.size();
 		UINT32 numRenderables = (UINT32)mRenderables.size();
@@ -662,9 +661,17 @@ namespace bs { namespace ct
 			{
 			{
 				bool isOverlayCamera = cameras[i]->getFlags().isSet(CameraFlag::Overlay);
 				bool isOverlayCamera = cameras[i]->getFlags().isSet(CameraFlag::Overlay);
 				if (!isOverlayCamera)
 				if (!isOverlayCamera)
-					render(frameInfo, rtInfo, i);
+				{
+					RendererCamera* viewInfo = mCameras[cameras[i]];
+
+					render(viewInfo, delta);
+				}
 				else
 				else
-					renderOverlay(frameInfo, rtInfo, i);
+				{
+					bool clear = i == 0;
+
+					renderOverlay(cameras[i], clear);
+				}
 			}
 			}
 		}
 		}
 
 
@@ -680,23 +687,19 @@ namespace bs { namespace ct
 		gProfilerCPU().endSample("renderAllCore");
 		gProfilerCPU().endSample("renderAllCore");
 	}
 	}
 
 
-	void RenderBeast::render(const RendererFrame& frameInfo, RendererRenderTarget& rtInfo, UINT32 camIdx)
+	void RenderBeast::render(RendererCamera* viewInfo, float frameDelta)
 	{
 	{
 		gProfilerCPU().beginSample("Render");
 		gProfilerCPU().beginSample("Render");
 
 
-		const Camera* camera = rtInfo.cameras[camIdx];
-		RendererCamera* rendererCam = mCameras[camera];
-		SPtr<GpuParamBlockBuffer> perCameraBuffer = rendererCam->getPerViewBuffer();
-		perCameraBuffer->flushToGPU();
+		const Camera* sceneCamera = viewInfo->getSceneCamera();
 
 
-		assert(!camera->getFlags().isSet(CameraFlag::Overlay));
+		SPtr<GpuParamBlockBuffer> perCameraBuffer = viewInfo->getPerViewBuffer();
+		perCameraBuffer->flushToGPU();
 
 
-		Matrix4 proj = camera->getProjectionMatrixRS();
-		Matrix4 view = camera->getViewMatrix();
-		Matrix4 viewProj = proj * view;
+		Matrix4 viewProj = viewInfo->getViewProjMatrix();
 
 
 		// Assign camera and per-call data to all relevant renderables
 		// Assign camera and per-call data to all relevant renderables
-		const Vector<bool>& visibility = rendererCam->getVisibilityMask();
+		const Vector<bool>& visibility = viewInfo->getVisibilityMask();
 		UINT32 numRenderables = (UINT32)mRenderables.size();
 		UINT32 numRenderables = (UINT32)mRenderables.size();
 		for (UINT32 i = 0; i < numRenderables; i++)
 		for (UINT32 i = 0; i < numRenderables; i++)
 		{
 		{
@@ -713,49 +716,56 @@ namespace bs { namespace ct
 			}
 			}
 		}
 		}
 
 
-		rendererCam->beginRendering(true);
+		viewInfo->beginRendering(true);
 
 
-		SPtr<RenderTargets> renderTargets = rendererCam->getRenderTargets();
+		SPtr<RenderTargets> renderTargets = viewInfo->getRenderTargets();
 		renderTargets->bindGBuffer();
 		renderTargets->bindGBuffer();
 
 
-		//// Trigger pre-base-pass callbacks
+		// Trigger pre-base-pass callbacks
 		auto iterRenderCallback = mCallbacks.begin();
 		auto iterRenderCallback = mCallbacks.begin();
-		while(iterRenderCallback != mCallbacks.end())
+
+		if (viewInfo->checkTriggerCallbacks())
 		{
 		{
-			RendererExtension* extension = *iterRenderCallback;
-			if (extension->getLocation() != RenderLocation::PreBasePass)
-				break;
-			
-			if (extension->check(*camera))
-				extension->render(*camera);
+			while (iterRenderCallback != mCallbacks.end())
+			{
+				RendererExtension* extension = *iterRenderCallback;
+				if (extension->getLocation() != RenderLocation::PreBasePass)
+					break;
 
 
-			++iterRenderCallback;
+				if (extension->check(*sceneCamera))
+					extension->render(*sceneCamera);
+
+				++iterRenderCallback;
+			}
 		}
 		}
 
 
-		//// Render base pass
-		const Vector<RenderQueueElement>& opaqueElements = rendererCam->getOpaqueQueue()->getSortedElements();
+		// Render base pass
+		const Vector<RenderQueueElement>& opaqueElements = viewInfo->getOpaqueQueue()->getSortedElements();
 		for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
 		for (auto iter = opaqueElements.begin(); iter != opaqueElements.end(); ++iter)
 		{
 		{
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
-			renderElement(*renderElem, iter->passIdx, iter->applyPass, frameInfo, viewProj);
+			renderElement(*renderElem, iter->passIdx, iter->applyPass, viewProj);
 		}
 		}
 
 
-		//// Trigger post-base-pass callbacks
-		while (iterRenderCallback != mCallbacks.end())
+		// Trigger post-base-pass callbacks
+		if (viewInfo->checkTriggerCallbacks())
 		{
 		{
-			RendererExtension* extension = *iterRenderCallback;
-			if (extension->getLocation() != RenderLocation::PostBasePass)
-				break;
+			while (iterRenderCallback != mCallbacks.end())
+			{
+				RendererExtension* extension = *iterRenderCallback;
+				if (extension->getLocation() != RenderLocation::PostBasePass)
+					break;
 
 
-			if (extension->check(*camera))
-				extension->render(*camera);
+				if (extension->check(*sceneCamera))
+					extension->render(*sceneCamera);
 
 
-			++iterRenderCallback;
+				++iterRenderCallback;
+			}
 		}
 		}
 
 
 		renderTargets->bindSceneColor(true);
 		renderTargets->bindSceneColor(true);
 
 
-		//// Render light pass
+		// Render light pass
 		{
 		{
 			mDirLightMat->bind(renderTargets, perCameraBuffer);
 			mDirLightMat->bind(renderTargets, perCameraBuffer);
 			for (auto& light : mDirectionalLights)
 			for (auto& light : mDirectionalLights)
@@ -777,8 +787,8 @@ namespace bs { namespace ct
 				if (!light.internal->getIsActive())
 				if (!light.internal->getIsActive())
 					continue;
 					continue;
 
 
-				float distToLight = (light.internal->getBounds().getCenter() - camera->getPosition()).squaredLength();
-				float boundRadius = light.internal->getBounds().getRadius() * 1.05f + camera->getNearClipDistance() * 2.0f;
+				float distToLight = (light.internal->getBounds().getCenter() - viewInfo->getViewOrigin()).squaredLength();
+				float boundRadius = light.internal->getBounds().getRadius() * 1.05f + viewInfo->getNearPlane() * 2.0f;
 
 
 				bool cameraInLightGeometry = distToLight < boundRadius * boundRadius;
 				bool cameraInLightGeometry = distToLight < boundRadius * boundRadius;
 				if (!cameraInLightGeometry)
 				if (!cameraInLightGeometry)
@@ -798,8 +808,8 @@ namespace bs { namespace ct
 				if (!light.internal->getIsActive())
 				if (!light.internal->getIsActive())
 					continue;
 					continue;
 
 
-				float distToLight = (light.internal->getBounds().getCenter() - camera->getPosition()).squaredLength();
-				float boundRadius = light.internal->getBounds().getRadius() * 1.05f + camera->getNearClipDistance() * 2.0f;
+				float distToLight = (light.internal->getBounds().getCenter() - viewInfo->getViewOrigin()).squaredLength();
+				float boundRadius = light.internal->getBounds().getRadius() * 1.05f + viewInfo->getNearPlane() * 2.0f;
 
 
 				bool cameraInLightGeometry = distToLight < boundRadius * boundRadius;
 				bool cameraInLightGeometry = distToLight < boundRadius * boundRadius;
 				if (cameraInLightGeometry)
 				if (cameraInLightGeometry)
@@ -813,7 +823,7 @@ namespace bs { namespace ct
 		}
 		}
 
 
 		// Render skybox (if any)
 		// Render skybox (if any)
-		SPtr<Texture> skyTexture = camera->getSkybox();
+		SPtr<Texture> skyTexture = viewInfo->getSkybox();
 		if (skyTexture != nullptr && skyTexture->getProperties().getTextureType() == TEX_TYPE_CUBE_MAP)
 		if (skyTexture != nullptr && skyTexture->getProperties().getTextureType() == TEX_TYPE_CUBE_MAP)
 		{
 		{
 			mSkyboxMat->bind(perCameraBuffer);
 			mSkyboxMat->bind(perCameraBuffer);
@@ -826,65 +836,84 @@ namespace bs { namespace ct
 		renderTargets->bindSceneColor(false);
 		renderTargets->bindSceneColor(false);
 
 
 		// Render transparent objects (TODO - No lighting yet)
 		// Render transparent objects (TODO - No lighting yet)
-		const Vector<RenderQueueElement>& transparentElements = rendererCam->getTransparentQueue()->getSortedElements();
+		const Vector<RenderQueueElement>& transparentElements = viewInfo->getTransparentQueue()->getSortedElements();
 		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
 		for (auto iter = transparentElements.begin(); iter != transparentElements.end(); ++iter)
 		{
 		{
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
 			BeastRenderableElement* renderElem = static_cast<BeastRenderableElement*>(iter->renderElem);
-			renderElement(*renderElem, iter->passIdx, iter->applyPass, frameInfo, viewProj);
+			renderElement(*renderElem, iter->passIdx, iter->applyPass, viewProj);
 		}
 		}
 
 
-		//// Trigger post-light-pass callbacks
-		while (iterRenderCallback != mCallbacks.end())
+		// Trigger post-light-pass callbacks
+		if (viewInfo->checkTriggerCallbacks())
 		{
 		{
-			RendererExtension* extension = *iterRenderCallback;
-			if (extension->getLocation() != RenderLocation::PostLightPass)
-				break;
+			while (iterRenderCallback != mCallbacks.end())
+			{
+				RendererExtension* extension = *iterRenderCallback;
+				if (extension->getLocation() != RenderLocation::PostLightPass)
+					break;
 
 
-			if (extension->check(*camera))
-				extension->render(*camera);
+				if (extension->check(*sceneCamera))
+					extension->render(*sceneCamera);
 
 
-			++iterRenderCallback;
+				++iterRenderCallback;
+			}
+		}
+
+		// Post-processing and final resolve
+		if (viewInfo->checkRunPostProcessing())
+		{
+			// TODO - If GBuffer has multiple samples, I should resolve them before post-processing
+			PostProcessing::instance().postProcess(viewInfo, renderTargets->getSceneColorRT(), frameDelta);
 		}
 		}
+		else
+		{
+			// Just copy from scene color to output if no post-processing
+			RenderAPI& rapi = RenderAPI::instance();
+			SPtr<RenderTarget> target = viewInfo->getFinalTarget();
+			Rect2 viewportArea = viewInfo->getViewportRect();
 
 
-		// TODO - If GBuffer has multiple samples, I should resolve them before post-processing
-		PostProcessing::instance().postProcess(renderTargets->getSceneColorRT(),
-			camera, rendererCam->getPPInfo(), frameInfo.delta);
+			rapi.setRenderTarget(target);
+			rapi.setViewport(viewportArea);
 
 
-		//// Trigger overlay callbacks
-		while (iterRenderCallback != mCallbacks.end())
+			SPtr<Texture> sceneColor = renderTargets->getSceneColorRT()->getColorTexture(0);
+			gRendererUtility().blit(sceneColor);
+		}
+
+		// Trigger overlay callbacks
+		if (viewInfo->checkTriggerCallbacks())
 		{
 		{
-			RendererExtension* extension = *iterRenderCallback;
-			if (extension->getLocation() != RenderLocation::Overlay)
-				break;
+			while (iterRenderCallback != mCallbacks.end())
+			{
+				RendererExtension* extension = *iterRenderCallback;
+				if (extension->getLocation() != RenderLocation::Overlay)
+					break;
 
 
-			if (extension->check(*camera))
-				extension->render(*camera);
+				if (extension->check(*sceneCamera))
+					extension->render(*sceneCamera);
 
 
-			++iterRenderCallback;
+				++iterRenderCallback;
+			}
 		}
 		}
 
 
-		rendererCam->endRendering();
+		viewInfo->endRendering();
 
 
 		gProfilerCPU().endSample("Render");
 		gProfilerCPU().endSample("Render");
 	}
 	}
 
 
-	void RenderBeast::renderOverlay(const RendererFrame& frameInfo, RendererRenderTarget& rtData, UINT32 camIdx)
+	void RenderBeast::renderOverlay(const Camera* camera, bool clear)
 	{
 	{
 		gProfilerCPU().beginSample("RenderOverlay");
 		gProfilerCPU().beginSample("RenderOverlay");
 
 
-		const Camera* camera = rtData.cameras[camIdx];
-		assert(camera->getFlags().isSet(CameraFlag::Overlay));
-
 		SPtr<Viewport> viewport = camera->getViewport();
 		SPtr<Viewport> viewport = camera->getViewport();
 		RendererCamera* rendererCam = mCameras[camera];
 		RendererCamera* rendererCam = mCameras[camera];
 		rendererCam->getPerViewBuffer()->flushToGPU();
 		rendererCam->getPerViewBuffer()->flushToGPU();
 
 
 		rendererCam->beginRendering(false);
 		rendererCam->beginRendering(false);
 
 
-		SPtr<RenderTarget> target = rtData.target;
+		SPtr<RenderTarget> target = camera->getViewport()->getTarget();
 
 
 		// If first camera in render target, prepare the render target
 		// If first camera in render target, prepare the render target
-		if (camIdx == 0)
+		if (clear)
 		{
 		{
 			RenderAPI::instance().setRenderTarget(target);
 			RenderAPI::instance().setRenderTarget(target);
 
 
@@ -931,8 +960,8 @@ namespace bs { namespace ct
 		gProfilerCPU().endSample("RenderOverlay");
 		gProfilerCPU().endSample("RenderOverlay");
 	}
 	}
 	
 	
-	void RenderBeast::renderElement(const BeastRenderableElement& element, UINT32 passIdx, bool bindPass,
-		const RendererFrame& frameInfo, const Matrix4& viewProj)
+	void RenderBeast::renderElement(const BeastRenderableElement& element, UINT32 passIdx, bool bindPass, 
+									const Matrix4& viewProj)
 	{
 	{
 		SPtr<Material> material = element.material;
 		SPtr<Material> material = element.material;