Explorar el Código

Renderer: Refactored visibility calculations so they are neatly encapsulated within the new RendererViewGroup class

BearishSun hace 8 años
padre
commit
3e1bd8a8a6

+ 1 - 0
Source/CMakeLists.txt

@@ -289,6 +289,7 @@ endif()
 
 ## Local experimental projects (not part of main repository)
 add_subdirectory_optional(Experimental/PBS)
+add_subdirectory_optional(Experimental/Shadows)
 
 ## Managed projects
 if(MSVC)

+ 16 - 8
Source/RenderBeast/Include/BsImageBasedLighting.h

@@ -8,6 +8,9 @@
 
 namespace bs { namespace ct
 {
+	struct SceneInfo;
+	class RendererViewGroup;
+
 	/** @addtogroup RenderBeast
 	 *  @{
 	 */
@@ -26,13 +29,16 @@ namespace bs { namespace ct
 	};
 
 	/** Contains GPU buffers used by the renderer to manipulate reflection probes. */
-	class GPUReflProbeData
+	class VisibleReflProbeData
 	{
 	public:
-		GPUReflProbeData();
+		VisibleReflProbeData();
 
-		/** Updates the internal buffers with a new set of probes. */
-		void setProbes(const Vector<ReflProbeData>& probeData, UINT32 numProbes);
+		/** 
+		 * Updates the internal buffers with a new set of refl. probes. Before calling make sure that probe visibility has
+		 * been calculated for the provided view group.
+		 */
+		void update(const SceneInfo& sceneInfo, const RendererViewGroup& viewGroup);
 
 		/** Returns a GPU bindable buffer containing information about every reflection probe. */
 		SPtr<GpuBuffer> getProbeBuffer() const { return mProbeBuffer; }
@@ -42,8 +48,10 @@ namespace bs { namespace ct
 
 	private:
 		SPtr<GpuBuffer> mProbeBuffer;
-
 		UINT32 mNumProbes;
+
+		// Helper to avoid memory allocations
+		Vector<ReflProbeData> mReflProbeDataTemp;
 	};
 
 	BS_PARAM_BLOCK_BEGIN(ReflProbeParamsParamDef)
@@ -121,7 +129,7 @@ namespace bs { namespace ct
 					 const SPtr<Texture>& preintegratedGF);
 
 		/** Binds all the active reflection probes. */
-		void setReflectionProbes(const GPUReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps, 
+		void setReflectionProbes(const VisibleReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps, 
 			bool capturingReflections);
 
 		/** Binds the sky reflection & irradiance textures. Set textures to null if not available. */
@@ -177,7 +185,7 @@ namespace bs { namespace ct
 			const SPtr<Texture>& preintegratedGF) = 0;
 
 		/** @copydoc TiledDeferredImageBasedLighting::setReflectionProbes() */
-		virtual void setReflectionProbes(const GPUReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps,
+		virtual void setReflectionProbes(const VisibleReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps,
 			bool capturingReflections) = 0;
 
 		/** @copydoc TiledDeferredImageBasedLighting::setSky() */
@@ -205,7 +213,7 @@ namespace bs { namespace ct
 			const SPtr<Texture>& preintegratedGF) override;
 
 		/** @copydoc ITiledDeferredImageBasedLightingMat::setReflectionProbes() */
-		void setReflectionProbes(const GPUReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps, 
+		void setReflectionProbes(const VisibleReflProbeData& probeData, const SPtr<Texture>& reflectionCubemaps, 
 			bool capturingReflections) override;
 
 		/** @copydoc ITiledDeferredImageBasedLightingMat::setSky() */

+ 2 - 2
Source/RenderBeast/Include/BsLightGrid.h

@@ -9,7 +9,7 @@
 
 namespace bs { namespace ct
 {
-	class GPUReflProbeData;
+	class VisibleReflProbeData;
 	class VisibleLightData;
 
 	/** @addtogroup RenderBeast
@@ -128,7 +128,7 @@ namespace bs { namespace ct
 		LightGrid();
 
 		/** Updates the light grid from the provided view. */
-		void updateGrid(const RendererView& view, const VisibleLightData& lightData, const GPUReflProbeData& probeData, 
+		void updateGrid(const RendererView& view, const VisibleLightData& lightData, const VisibleReflProbeData& probeData, 
 			bool noLighting);
 
 		/** 

+ 3 - 2
Source/RenderBeast/Include/BsLightRendering.h

@@ -10,6 +10,7 @@
 namespace bs { namespace ct
 {
 	struct SceneInfo;
+	class RendererViewGroup;
 
 	/** @addtogroup RenderBeast
 	 *  @{
@@ -75,9 +76,9 @@ namespace bs { namespace ct
 
 		/** 
 		 * Updates the internal buffers with a new set of lights. Before calling make sure that light visibility has
-		 * been calculated and assigned to @p sceneInfo.
+		 * been calculated for the provided view group.
 		 */
-		void setLights(const SceneInfo& sceneInfo);
+		void update(const SceneInfo& sceneInfo, const RendererViewGroup& viewGroup);
 
 		/** Returns a GPU bindable buffer containing information about every light. */
 		SPtr<GpuBuffer> getLightBuffer() const { return mLightBuffer; }

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

@@ -138,11 +138,11 @@ namespace bs
 		void renderAllCore(float time, float delta);
 
 		/**
-		 * Renders all provided views.
+		 * Renders all views in the provided view group.
 		 * 
 		 * @note	Core thread only. 
 		 */
-		void renderViews(RendererView** views, UINT32 numViews, const FrameInfo& frameInfo);
+		void renderViews(const RendererViewGroup& viewGroup, const FrameInfo& frameInfo);
 
 		/**
 		 * Renders all objects visible by the provided view.
@@ -214,7 +214,7 @@ namespace bs
 
 		//// Image based lighting
 		TiledDeferredImageBasedLightingMaterials* mTileDeferredImageBasedLightingMats = nullptr;
-		GPUReflProbeData* mGPUReflProbeData = nullptr;
+		VisibleReflProbeData* mVisibleReflProbeInfo = nullptr;
 		SPtr<Texture> mPreintegratedEnvBRDF;
 
 		//// Sky
@@ -227,8 +227,7 @@ namespace bs
 		SPtr<RenderBeastOptions> mCoreOptions;
 
 		// Helpers to avoid memory allocations
-		Vector<ReflProbeData> mReflProbeDataTemp;
-		Vector<bool> mReflProbeVisibilityTemp;
+		RendererViewGroup mMainViewGroup;
 
 		// Sim thread only fields
 		SPtr<RenderBeastOptions> mOptions;

+ 0 - 5
Source/RenderBeast/Include/BsRendererScene.h

@@ -47,11 +47,6 @@ namespace bs
 		// Buffers for various transient data that gets rebuilt every frame
 		//// Rebuilt every frame
 		mutable Vector<bool> renderableReady;
-
-		//// Rebuilt for every set of views
-		mutable Vector<bool> renderableVisibility;
-		mutable Vector<bool> radialLightVisibility;
-		mutable Vector<bool> spotLightVisibility;
 	};
 
 	/** Contains information about the scene (e.g. renderables, lights, cameras) required by the renderer. */

+ 40 - 0
Source/RenderBeast/Include/BsRendererView.h

@@ -13,6 +13,7 @@
 
 namespace bs { namespace ct
 {
+	struct SceneInfo;
 	class RendererLight;
 
 	/** @addtogroup RenderBeast
@@ -143,6 +144,7 @@ namespace bs { namespace ct
 		Vector<bool> renderables;
 		Vector<bool> radialLights;
 		Vector<bool> spotLights;
+		Vector<bool> reflProbes;
 	};
 
 	/** Information used for culling an object against a view. */
@@ -318,5 +320,43 @@ namespace bs { namespace ct
 		VisibilityInfo mVisibility;
 	};
 
+	/** Contains one or multiple RendererView%s that are in some way related. */
+	class RendererViewGroup
+	{
+	public:
+		RendererViewGroup() {}
+		RendererViewGroup(RendererView** views, UINT32 numViews);
+
+		/** 
+		 * Updates the internal list of views. This is more efficient than always constructing a new instance of this class
+		 * when views change, as internal buffers don't need to be re-allocated.
+		 */
+		void setViews(RendererView** views, UINT32 numViews);
+
+		/** Returns a view at the specified index. Index must be less than the value returned by getNumViews(). */
+		RendererView* getView(UINT32 idx) const { return mViews[idx]; }
+
+		/** Returns the total number of views in the group. */
+		UINT32 getNumViews() const { return (UINT32)mViews.size(); }
+
+		/** 
+		 * Returns information about visibility of various scene objects, from the perspective of all the views in the 
+		 * group (visibility will be true if the object is visible from any of the views. determineVisibility() must be
+		 * called whenever the scene or view information changes (usually every frame). 
+		 */
+		const VisibilityInfo& getVisibilityInfo() const { return mVisibility; }
+
+		/** 
+		 * Updates visibility information for the provided scene objects, from the perspective of all views in this group,
+		 * and updates the render queues of each individual view. Use getVisibilityInfo() to retrieve the calculated
+		 * visibility information.
+		 */
+		void determineVisibility(const SceneInfo& sceneInfo);
+
+	private:
+		Vector<RendererView*> mViews;
+		VisibilityInfo mVisibility;
+	};
+
 	/** @} */
 }}

+ 2 - 2
Source/RenderBeast/Include/BsShadowRendering.h

@@ -451,8 +451,8 @@ namespace bs { namespace ct
 	public:
 		ShadowRendering(UINT32 shadowMapSize);
 
-		/** For each visibile shadow casting light, renders a shadow map from its point of view. */
-		void renderShadowMaps(RendererScene& scene, const FrameInfo& frameInfo);
+		/** For each visible shadow casting light, renders a shadow map from its point of view. */
+		void renderShadowMaps(RendererScene& scene, const RendererViewGroup& viewGroup, const FrameInfo& frameInfo);
 
 		/** 
 		 * Renders shadow occlusion values for the specified light, into the currently bound render target. 

+ 32 - 7
Source/RenderBeast/Source/BsImageBasedLighting.cpp

@@ -19,15 +19,38 @@ namespace bs { namespace ct
 	ReflProbeParamsParamDef gReflProbeParamsParamDef;
 	TiledImageBasedLightingParamDef gTiledImageBasedLightingParamDef;
 
-	GPUReflProbeData::GPUReflProbeData()
+	VisibleReflProbeData::VisibleReflProbeData()
 		:mNumProbes(0)
 	{ }
 
-	void GPUReflProbeData::setProbes(const Vector<ReflProbeData>& probeData, UINT32 numProbes)
+	void VisibleReflProbeData::update(const SceneInfo& sceneInfo, const RendererViewGroup& viewGroup)
 	{
-		mNumProbes = numProbes;
+		const VisibilityInfo& visibility = viewGroup.getVisibilityInfo();
 
-		UINT32 size = numProbes * sizeof(ReflProbeData);
+		// Generate refl. probe data for the visible ones
+		UINT32 numProbes = (UINT32)sceneInfo.reflProbes.size();
+		for(UINT32 i = 0; i < numProbes; i++)
+		{
+			if (!visibility.reflProbes[i])
+				continue;
+
+			mReflProbeDataTemp.push_back(ReflProbeData());
+			sceneInfo.reflProbes[i].getParameters(mReflProbeDataTemp.back());
+		}
+
+		// Sort probes so bigger ones get accessed first, this way we overlay smaller ones on top of biggers ones when
+		// rendering
+		auto sorter = [](const ReflProbeData& lhs, const ReflProbeData& rhs)
+		{
+			return rhs.radius < lhs.radius;
+		};
+
+		std::sort(mReflProbeDataTemp.begin(), mReflProbeDataTemp.end(), sorter);
+
+		mNumProbes = (UINT32)mReflProbeDataTemp.size();
+
+		// Move refl. probe data into a GPU buffer
+		UINT32 size = mNumProbes * sizeof(ReflProbeData);
 		UINT32 curBufferSize;
 
 		if (mProbeBuffer != nullptr)
@@ -50,7 +73,9 @@ namespace bs { namespace ct
 		}
 
 		if (size > 0)
-			mProbeBuffer->writeData(0, size, probeData.data(), BWT_DISCARD);
+			mProbeBuffer->writeData(0, size, mReflProbeDataTemp.data(), BWT_DISCARD);
+
+		mReflProbeDataTemp.clear();
 	}
 
 	RendererReflectionProbe::RendererReflectionProbe(ReflectionProbe* probe)
@@ -195,7 +220,7 @@ namespace bs { namespace ct
 		RenderAPI::instance().dispatchCompute(numTilesX, numTilesY);
 	}
 
-	void TiledDeferredImageBasedLighting::setReflectionProbes(const GPUReflProbeData& probeData,
+	void TiledDeferredImageBasedLighting::setReflectionProbes(const VisibleReflProbeData& probeData,
 		const SPtr<Texture>& reflectionCubemaps, bool capturingReflections)
 	{
 		mImageBasedParams.reflectionProbesParam.set(probeData.getProbeBuffer());
@@ -388,7 +413,7 @@ namespace bs { namespace ct
 	}
 
 	template<int MSAA_COUNT>
-	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::setReflectionProbes(const GPUReflProbeData& probeData, 
+	void TTiledDeferredImageBasedLightingMat<MSAA_COUNT>::setReflectionProbes(const VisibleReflProbeData& probeData, 
 		const SPtr<Texture>& reflectionCubemaps, bool capturingReflections)
 	{
 		mInternal.setReflectionProbes(probeData, reflectionCubemaps, capturingReflections);

+ 1 - 1
Source/RenderBeast/Source/BsLightGrid.cpp

@@ -242,7 +242,7 @@ namespace bs { namespace ct
 		mGridParamBuffer = gLightGridParamDefDef.createBuffer();
 	}
 
-	void LightGrid::updateGrid(const RendererView& view, const VisibleLightData& lightData, const GPUReflProbeData& probeData,
+	void LightGrid::updateGrid(const RendererView& view, const VisibleLightData& lightData, const VisibleReflProbeData& probeData,
 		bool noLighting)
 	{
 		UINT32 width = view.getRenderTargets()->getWidth();

+ 5 - 3
Source/RenderBeast/Source/BsLightRendering.cpp

@@ -109,8 +109,10 @@ namespace bs { namespace ct
 		:mNumLights{}, mNumShadowedLights{}
 	{ }
 
-	void VisibleLightData::setLights(const SceneInfo& sceneInfo)
+	void VisibleLightData::update(const SceneInfo& sceneInfo, const RendererViewGroup& viewGroup)
 	{
+		const VisibilityInfo& visibility = viewGroup.getVisibilityInfo();
+
 		for (UINT32 i = 0; i < (UINT32)LightType::Count; i++)
 			mVisibleLights[i].clear();
 
@@ -122,7 +124,7 @@ namespace bs { namespace ct
 		UINT32 numRadialLights = (UINT32)sceneInfo.radialLights.size();
 		for(UINT32 i = 0; i < numRadialLights; i++)
 		{
-			if (!sceneInfo.radialLightVisibility[i])
+			if (!visibility.radialLights[i])
 				continue;
 
 			mVisibleLights[(UINT32)LightType::Radial].push_back(&sceneInfo.radialLights[i]);
@@ -131,7 +133,7 @@ namespace bs { namespace ct
 		UINT32 numSpotLights = (UINT32)sceneInfo.spotLights.size();
 		for (UINT32 i = 0; i < numSpotLights; i++)
 		{
-			if (!sceneInfo.spotLightVisibility[i])
+			if (!visibility.spotLights[i])
 				continue;
 
 			mVisibleLights[(UINT32)LightType::Spot].push_back(&sceneInfo.spotLights[i]);

+ 33 - 74
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -87,7 +87,7 @@ namespace bs { namespace ct
 
 		mPreintegratedEnvBRDF = TiledDeferredImageBasedLighting::generatePreintegratedEnvBRDF();
 		mVisibleLightInfo = bs_new<VisibleLightData>();
-		mGPUReflProbeData = bs_new<GPUReflProbeData>();
+		mVisibleReflProbeInfo = bs_new<VisibleReflProbeData>();
 		mLightGrid = bs_new<LightGrid>();
 
 		GpuResourcePool::startUp();
@@ -116,7 +116,7 @@ namespace bs { namespace ct
 		bs_delete(mSkyboxMat);
 		bs_delete(mSkyboxSolidColorMat);
 		bs_delete(mVisibleLightInfo);
-		bs_delete(mGPUReflProbeData);
+		bs_delete(mVisibleReflProbeInfo);
 		bs_delete(mLightGrid);
 		bs_delete(mFlatFramebufferToTextureMat);
 		bs_delete(mTiledDeferredLightingMats);
@@ -334,12 +334,6 @@ namespace bs { namespace ct
 		
 		FrameInfo frameInfo(delta, animData);
 
-		// Render shadow maps
-		//ShadowRendering::instance().renderShadowMaps(*mScene, frameInfo);
-
-		// Update reflection probes
-		updateLightProbes(frameInfo);
-
 		// Gather all views
 		Vector<RendererView*> views;
 		for (auto& rtInfo : sceneInfo.renderTargets)
@@ -356,8 +350,17 @@ namespace bs { namespace ct
 			}
 		}
 
+		mMainViewGroup.setViews(views.data(), (UINT32)views.size());
+		mMainViewGroup.determineVisibility(sceneInfo);
+
+		// Render shadow maps
+		//ShadowRendering::instance().renderShadowMaps(*mScene, mMainViewGroup, frameInfo);
+
+		// Update reflection probes
+		updateLightProbes(frameInfo);
+
 		// Render everything
-		renderViews(views.data(), (UINT32)views.size(), frameInfo);
+		renderViews(mMainViewGroup, frameInfo);
 
 		gProfilerGPU().endFrame();
 
@@ -371,84 +374,36 @@ namespace bs { namespace ct
 		gProfilerCPU().endSample("renderAllCore");
 	}
 
-	void RenderBeast::renderViews(RendererView** views, UINT32 numViews, const FrameInfo& frameInfo)
+	void RenderBeast::renderViews(const RendererViewGroup& viewGroup, const FrameInfo& frameInfo)
 	{
 		const SceneInfo& sceneInfo = mScene->getSceneInfo();
-
-		// Generate render queues per camera
-		sceneInfo.renderableVisibility.resize(sceneInfo.renderables.size(), false);
-		sceneInfo.renderableVisibility.assign(sceneInfo.renderableVisibility.size(), false);
-
-		for(UINT32 i = 0; i < numViews; i++)
-			views[i]->determineVisible(sceneInfo.renderables, sceneInfo.renderableCullInfos, &sceneInfo.renderableVisibility);
-
-		// Calculate light visibility for all views
-		UINT32 numRadialLights = (UINT32)sceneInfo.radialLights.size();
-		sceneInfo.radialLightVisibility.resize(numRadialLights, false);
-		sceneInfo.radialLightVisibility.assign(numRadialLights, false);
-
-		UINT32 numSpotLights = (UINT32)sceneInfo.spotLights.size();
-		sceneInfo.spotLightVisibility.resize(numSpotLights, false);
-		sceneInfo.spotLightVisibility.assign(numSpotLights, false);
-
-		for (UINT32 i = 0; i < numViews; i++)
-		{
-			views[i]->determineVisible(sceneInfo.radialLights, sceneInfo.radialLightWorldBounds, LightType::Radial,
-				&sceneInfo.radialLightVisibility);
-
-			views[i]->determineVisible(sceneInfo.spotLights, sceneInfo.spotLightWorldBounds, LightType::Spot,
-				&sceneInfo.spotLightVisibility);
-		}
+		const VisibilityInfo& visibility = viewGroup.getVisibilityInfo();
 
 		// Update GPU light data
-		mVisibleLightInfo->setLights(sceneInfo);
-
-		// Gemerate reflection probes and their GPU buffers
-		UINT32 numProbes = (UINT32)sceneInfo.reflProbes.size();
-
-		mReflProbeVisibilityTemp.resize(numProbes, false);
-		for (UINT32 i = 0; i < numViews; i++)
-			views[i]->calculateVisibility(sceneInfo.reflProbeWorldBounds, mReflProbeVisibilityTemp);
+		mVisibleLightInfo->update(sceneInfo, viewGroup);
 
-		for(UINT32 i = 0; i < numProbes; i++)
-		{
-			if (!mReflProbeVisibilityTemp[i])
-				continue;
-
-			mReflProbeDataTemp.push_back(ReflProbeData());
-			sceneInfo.reflProbes[i].getParameters(mReflProbeDataTemp.back());
-		}
-
-		// Sort probes so bigger ones get accessed first, this way we overlay smaller ones on top of biggers ones when
-		// rendering
-		auto sorter = [](const ReflProbeData& lhs, const ReflProbeData& rhs)
-		{
-			return rhs.radius < lhs.radius;
-		};
-
-		std::sort(mReflProbeDataTemp.begin(), mReflProbeDataTemp.end(), sorter);
-
-		mGPUReflProbeData->setProbes(mReflProbeDataTemp, numProbes);
-
-		mReflProbeDataTemp.clear();
-		mReflProbeVisibilityTemp.clear();
+		// Update reflection probe data
+		mVisibleReflProbeInfo->update(sceneInfo, viewGroup);
 
 		// Update various buffers required by each renderable
 		UINT32 numRenderables = (UINT32)sceneInfo.renderables.size();
 		for (UINT32 i = 0; i < numRenderables; i++)
 		{
-			if (!sceneInfo.renderableVisibility[i])
+			if (!visibility.renderables[i])
 				continue;
 
 			mScene->prepareRenderable(i, frameInfo);
 		}
 
+		UINT32 numViews = viewGroup.getNumViews();
 		for (UINT32 i = 0; i < numViews; i++)
 		{
-			if (views[i]->getProperties().isOverlay)
-				renderOverlay(views[i]);
+			RendererView* view = viewGroup.getView(i);
+
+			if (view->getProperties().isOverlay)
+				renderOverlay(view);
 			else
-				renderView(views[i], frameInfo.timeDelta);
+				renderView(view, frameInfo.timeDelta);
 		}
 	}
 
@@ -481,7 +436,7 @@ namespace bs { namespace ct
 		viewInfo->beginRendering(true);
 
 		// Prepare light grid required for transparent object rendering
-		mLightGrid->updateGrid(*viewInfo, *mVisibleLightInfo, *mGPUReflProbeData, viewProps.noLighting);
+		mLightGrid->updateGrid(*viewInfo, *mVisibleLightInfo, *mVisibleReflProbeInfo, viewProps.noLighting);
 
 		SPtr<GpuParamBlockBuffer> gridParams;
 		SPtr<GpuBuffer> gridLightOffsetsAndSize, gridLightIndices;
@@ -493,7 +448,7 @@ namespace bs { namespace ct
 		ITiledDeferredImageBasedLightingMat* imageBasedLightingMat =
 			mTileDeferredImageBasedLightingMats->get(numSamples);
 
-		imageBasedLightingMat->setReflectionProbes(*mGPUReflProbeData, mReflCubemapArrayTex, viewProps.renderingReflections);
+		imageBasedLightingMat->setReflectionProbes(*mVisibleReflProbeInfo, mReflCubemapArrayTex, viewProps.renderingReflections);
 
 		float skyBrightness = 1.0f;
 		if (mSkybox != nullptr)
@@ -538,7 +493,7 @@ namespace bs { namespace ct
 				element.gridProbeOffsetsAndSizeParam.set(gridProbeOffsetsAndSize);
 
 				iblParams.reflectionProbeIndicesParam.set(gridProbeIndices);
-				iblParams.reflectionProbesParam.set(mGPUReflProbeData->getProbeBuffer());
+				iblParams.reflectionProbesParam.set(mVisibleReflProbeInfo->getProbeBuffer());
 
 				iblParams.skyReflectionsTexParam.set(mSkyboxFilteredReflections);
 				iblParams.skyIrradianceTexParam.set(mSkyboxIrradiance);
@@ -994,6 +949,7 @@ namespace bs { namespace ct
 
 	void RenderBeast::captureSceneCubeMap(const SPtr<Texture>& cubemap, const Vector3& position, bool hdr, const FrameInfo& frameInfo)
 	{
+		const SceneInfo& sceneInfo = mScene->getSceneInfo();
 		auto& texProps = cubemap->getProperties();
 
 		Matrix4 projTransform = Matrix4::projectionPerspective(Degree(90.0f), 1.0f, 0.05f, 1000.0f);
@@ -1098,12 +1054,15 @@ namespace bs { namespace ct
 			views[i].setView(viewDesc);
 			views[i].updatePerViewBuffer();
 
-			const SceneInfo& sceneInfo = mScene->getSceneInfo();
 			views[i].determineVisible(sceneInfo.renderables, sceneInfo.renderableCullInfos);
 		}
 
 		RendererView* viewPtrs[] = { &views[0], &views[1], &views[2], &views[3], &views[4], &views[5] };
-		renderViews(viewPtrs, 6, frameInfo);
+
+		RendererViewGroup viewGroup(viewPtrs, 6);
+		viewGroup.determineVisibility(sceneInfo);
+
+		renderViews(viewGroup, frameInfo);
 	}
 
 }}

+ 61 - 0
Source/RenderBeast/Source/BsRendererView.cpp

@@ -9,6 +9,7 @@
 #include "BsRendererUtility.h"
 #include "BsLightRendering.h"
 #include "BsGpuParamsSet.h"
+#include "BsRendererScene.h"
 
 namespace bs { namespace ct
 {
@@ -459,4 +460,64 @@ namespace bs { namespace ct
 
 	template class SkyboxMat<true>;
 	template class SkyboxMat<false>;
+
+	RendererViewGroup::RendererViewGroup(RendererView** views, UINT32 numViews)
+	{
+		setViews(views, numViews);
+	}
+
+	void RendererViewGroup::setViews(RendererView** views, UINT32 numViews)
+	{
+		mViews.clear();
+
+		for (UINT32 i = 0; i < numViews; i++)
+			mViews.push_back(views[i]);
+	}
+
+	void RendererViewGroup::determineVisibility(const SceneInfo& sceneInfo)
+	{
+		UINT32 numViews = (UINT32)mViews.size();
+
+		// Generate render queues per camera
+		mVisibility.renderables.resize(sceneInfo.renderables.size(), false);
+		mVisibility.renderables.assign(sceneInfo.renderables.size(), false);
+
+		for(UINT32 i = 0; i < numViews; i++)
+			mViews[i]->determineVisible(sceneInfo.renderables, sceneInfo.renderableCullInfos, &mVisibility.renderables);
+
+		// Calculate light visibility for all views
+		UINT32 numRadialLights = (UINT32)sceneInfo.radialLights.size();
+		mVisibility.radialLights.resize(numRadialLights, false);
+		mVisibility.radialLights.assign(numRadialLights, false);
+
+		UINT32 numSpotLights = (UINT32)sceneInfo.spotLights.size();
+		mVisibility.spotLights.resize(numSpotLights, false);
+		mVisibility.spotLights.assign(numSpotLights, false);
+
+		for (UINT32 i = 0; i < numViews; i++)
+		{
+			mViews[i]->determineVisible(sceneInfo.radialLights, sceneInfo.radialLightWorldBounds, LightType::Radial,
+				&mVisibility.radialLights);
+
+			mViews[i]->determineVisible(sceneInfo.spotLights, sceneInfo.spotLightWorldBounds, LightType::Spot,
+				&mVisibility.spotLights);
+		}
+
+		// Calculate refl. probe visibility for all views
+		UINT32 numProbes = (UINT32)sceneInfo.reflProbes.size();
+		mVisibility.reflProbes.resize(numProbes, false);
+		mVisibility.reflProbes.assign(numProbes, false);
+
+		// Note: Per-view visibility for refl. probes currently isn't calculated
+		for (UINT32 i = 0; i < numViews; i++)
+		{
+			const auto& viewProps = mViews[i]->getProperties();
+
+			// Don't recursively render reflection probes when generating reflection probe maps
+			if (viewProps.renderingReflections)
+				continue;
+
+			mViews[i]->calculateVisibility(sceneInfo.reflProbeWorldBounds, mVisibility.reflProbes);
+		}
+	}
 }}

+ 5 - 3
Source/RenderBeast/Source/BsShadowRendering.cpp

@@ -564,7 +564,8 @@ namespace bs { namespace ct
 		mShadowCubemaps.clear();
 	}
 
-	void ShadowRendering::renderShadowMaps(RendererScene& scene, const FrameInfo& frameInfo)
+	void ShadowRendering::renderShadowMaps(RendererScene& scene, const RendererViewGroup& viewGroup, 
+		const FrameInfo& frameInfo)
 	{
 		// Note: Currently all shadows are dynamic and are rebuilt every frame. I should later added support for static
 		// shadow maps which can be used for immovable lights. Such a light can then maintain a set of shadow maps,
@@ -575,6 +576,7 @@ namespace bs { namespace ct
 		// used for adding high quality shadows on specific objects (e.g. important characters during cinematics).
 
 		const SceneInfo& sceneInfo = scene.getSceneInfo();
+		const VisibilityInfo& visibility = viewGroup.getVisibilityInfo();
 		
 		// Clear all transient data from last frame
 		mShadowInfos.clear();
@@ -604,7 +606,7 @@ namespace bs { namespace ct
 
 			// Note: I'm using visibility across all views, while I could be using visibility for every view individually,
 			// if I kept that information somewhere
-			if (!light.internal->getCastsShadow() || !sceneInfo.spotLightVisibility[i])
+			if (!light.internal->getCastsShadow() || !visibility.spotLights[i])
 				continue;
 
 			ShadowMapOptions options;
@@ -630,7 +632,7 @@ namespace bs { namespace ct
 
 			// Note: I'm using visibility across all views, while I could be using visibility for every view individually,
 			// if I kept that information somewhere
-			if (!light.internal->getCastsShadow() || !sceneInfo.radialLightVisibility[i])
+			if (!light.internal->getCastsShadow() || !visibility.radialLights[i])
 				continue;
 
 			ShadowMapOptions options;