Преглед изворни кода

Code for reflection cubemap sampling

BearishSun пре 8 година
родитељ
комит
dead930f9c

+ 79 - 3
Data/Raw/Engine/Includes/ReflectionCubemapSampling.bslinc

@@ -6,17 +6,36 @@ Technique : base("ReflectionCubemapSampling") =
 	{
 	{
 		Common = 
 		Common = 
 		{
 		{
+			struct ReflProbeData
+			{
+				float3 position;
+				float radius;
+				float3 boxExtents;
+				float4x4 invBoxTransform;
+				float transitionDistance;
+				uint cubemapIdx;
+				uint type; // 0 - Sphere, 1 - Box
+			};
+		
 			TextureCube gSkyCubemapTex;
 			TextureCube gSkyCubemapTex;
 			SamplerState gSkyCubemapSamp;
 			SamplerState gSkyCubemapSamp;
+			
+			TextureCubeArray gReflProbeCubmaps;
+			SamplerState gReflProbeSamp;
+			
+			StructuredBuffer<ReflProbeData> gReflectionProbes;	
 
 
-			cbuffer ReflectionParams
+			cbuffer ReflProbeParams
 			{
 			{
-				int gSkyNumMips;
+				uint gReflCubemapNumMips;
+				uint gNumProbes;
+				uint gSkyCubemapAvailable;
+				uint gSkyCubemapNumMips;
 			}	
 			}	
 			
 			
 			float3 getSkyReflection(float3 dir, float roughness)
 			float3 getSkyReflection(float3 dir, float roughness)
 			{
 			{
-				float mipLevel = mapRoughnessToMipLevel(roughness, gSkyNumMips);
+				float mipLevel = mapRoughnessToMipLevel(roughness, gReflCubemapNumMips);
 				float3 reflection = gSkyCubemapTex.SampleLevel(gSkyCubemapSamp, dir, mipLevel);
 				float3 reflection = gSkyCubemapTex.SampleLevel(gSkyCubemapSamp, dir, mipLevel);
 
 
 				return reflection;
 				return reflection;
@@ -103,6 +122,63 @@ Technique : base("ReflectionCubemapSampling") =
 				
 				
 				return lookupDir;
 				return lookupDir;
 			}
 			}
+			
+			float3 gatherReflectionRadiance(float3 worldPos, float3 dir, float roughness, uint probeOffset, uint numProbes)
+			{
+				#if FIXED_REFLECTION_COLOR
+					return float3(1.0f, 1.0f, 1.0f);
+				#else
+				
+				float mipLevel = mapRoughnessToMipLevel(roughness, gReflCubemapNumMips);
+				
+				float3 output = 0;
+				float leftoverContribution = 1.0f;
+				for(uint i = 0; i < numProbes; i++)
+				{
+					if(leftoverContribution < 0.001f)
+						break;
+							
+					uint probeIdx = gReflectionProbeIndices[probeOffset + i];
+					ReflProbeData probeData = gReflectionProbes[probeIdx];
+					
+					float3 probeToPos = worldPos - probeData.position;
+					float distToProbe = length(probeToPos);
+					float normalizedDist = saturate(distToProbe / probeData.radius);
+								
+					if(distToProbe <= probeData.radius)
+					{
+						float3 correctedDir;
+						float contribution = 0;
+						if(probeData.type == 0) // Sphere
+						{
+							correctedDir = getLookupForSphereProxy(worldPos, dir, probeData.position, probeData.radius);
+							contibution = getSphereReflectionContribution(normalizedDist);
+						}
+						else if(probeData.type == 1) // Box
+						{
+							correctedDir = getLookupForBoxProxy(worldPos, dir, probeData.position, probeData.boxExtents, probeData.invBoxTransform, probeData.transitionDistance, contribution);
+						}
+						
+						float4 sample = gReflProbeCubmaps.SampleLevel(gReflProbeSamp, float4(correctedDir, probeData.cubemapIdx), mipLevel);
+						sample *= contribution;
+						
+						output += sample * leftoverContribution; 
+						leftoverContribution *= (1.0f - contribution);
+					}
+				}
+				
+				if(gSkyCubemapAvailable > 0)
+				{
+					float skyMipLevel = mapRoughnessToMipLevel(roughness, gSkyCubemapNumMips);
+					float4 sample = gSkyCubemapTex.SampleLevel(gSkyCubemapSamp, dir, skyMipLevel);
+					
+					output += sample * leftoverContribution; 
+				}
+						
+				return output;
+						
+				#endif
+			}
 		};
 		};
 	};
 	};
 };
 };

+ 2 - 0
Source/RenderBeast/CMakeSources.cmake

@@ -12,6 +12,7 @@ set(BS_RENDERBEAST_INC_NOFILTER
 	"Include/BsRendererCamera.h"
 	"Include/BsRendererCamera.h"
 	"Include/BsRendererObject.h"
 	"Include/BsRendererObject.h"
 	"Include/BsLightGrid.h"
 	"Include/BsLightGrid.h"
+	"Include/BsReflectionProbeSampling.h"
 )
 )
 
 
 set(BS_RENDERBEAST_SRC_NOFILTER
 set(BS_RENDERBEAST_SRC_NOFILTER
@@ -27,6 +28,7 @@ set(BS_RENDERBEAST_SRC_NOFILTER
 	"Source/BsRendererCamera.cpp"
 	"Source/BsRendererCamera.cpp"
 	"Source/BsRendererObject.cpp"
 	"Source/BsRendererObject.cpp"
 	"Source/BsLightGrid.cpp"
 	"Source/BsLightGrid.cpp"
+	"Source/BsReflectionProbeSampling.cpp"
 )
 )
 
 
 source_group("Header Files" FILES ${BS_RENDERBEAST_INC_NOFILTER})
 source_group("Header Files" FILES ${BS_RENDERBEAST_INC_NOFILTER})

+ 76 - 0
Source/RenderBeast/Include/BsReflectionProbeSampling.h

@@ -0,0 +1,76 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsRenderBeastPrerequisites.h"
+#include "BsRendererMaterial.h"
+#include "BsParamBlocks.h"
+
+namespace bs { namespace ct
+{
+	/** @addtogroup RenderBeast
+	 *  @{
+	 */
+
+	/** Information about a single reflection probe, as seen by the lighting shader. */
+	struct ReflProbeData
+	{
+		Vector3 position;
+		float radius;
+		Vector3 boxExtents;
+		Matrix4 invBoxTransform;
+		float transitionDistance;
+		UINT32 cubemapIdx;
+		UINT32 type;
+	};
+
+	/** Contains GPU buffers used by the renderer to manipulate reflection probes. */
+	class GPUReflProbeData
+	{
+	public:
+		GPUReflProbeData();
+
+		/** Updates the internal buffers with a new set of probes. */
+		void setProbes(const Vector<ReflProbeData>& probeData, UINT32 numProbes);
+
+		/** Returns a GPU bindable buffer containing information about every reflection probe. */
+		SPtr<GpuBuffer> getProbeBuffer() const { return mProbeBuffer; }
+
+		/** Returns the number of reflection probes in the probe buffer. */
+		UINT32 getNumProbes() const { return mNumProbes; }
+
+	private:
+		SPtr<GpuBuffer> mProbeBuffer;
+
+		UINT32 mNumProbes;
+	};
+
+	BS_PARAM_BLOCK_BEGIN(ReflProbeParamsParamDef)
+		BS_PARAM_BLOCK_ENTRY(INT32, gReflCubemapNumMips)
+		BS_PARAM_BLOCK_ENTRY(INT32, gNumProbes)
+		BS_PARAM_BLOCK_ENTRY(INT32, gSkyCubemapAvailable)
+		BS_PARAM_BLOCK_ENTRY(INT32, gSkyCubemapNumMips)
+	BS_PARAM_BLOCK_END
+
+	extern ReflProbeParamsParamDef gReflProbeParamsParamDef;
+
+	/**	Renderer information specific to a single reflection probe. */
+	class RendererReflectionProbe
+	{
+	public:
+		RendererReflectionProbe(ReflectionProbe* probe);
+
+		/** Populates the structure with reflection probe parameters. */
+		void getParameters(ReflProbeData& output) const;
+
+		ReflectionProbe* probe;
+		UINT32 arrayIdx;
+		SPtr<Texture> texture;
+		bool customTexture : 1;
+		bool textureDirty : 1;
+		bool arrayDirty : 1;
+		bool errorFlagged : 1;
+	};
+
+	/** @} */
+}}

+ 6 - 13
Source/RenderBeast/Include/BsRenderBeast.h

@@ -8,6 +8,7 @@
 #include "BsSamplerOverrides.h"
 #include "BsSamplerOverrides.h"
 #include "BsRendererMaterial.h"
 #include "BsRendererMaterial.h"
 #include "BsLightRendering.h"
 #include "BsLightRendering.h"
+#include "BsReflectionProbeSampling.h"
 #include "BsObjectRendering.h"
 #include "BsObjectRendering.h"
 #include "BsPostProcessing.h"
 #include "BsPostProcessing.h"
 #include "BsRendererCamera.h"
 #include "BsRendererCamera.h"
@@ -65,18 +66,6 @@ namespace bs
 			const RendererAnimationData& animData;
 			const RendererAnimationData& animData;
 		};
 		};
 
 
-		/** Information about an active reflection probe. */
-		struct ReflProbeInfo
-		{
-			ReflectionProbe* probe;
-			UINT32 arrayIdx;
-			SPtr<Texture> texture;
-			bool customTexture : 1;
-			bool textureDirty : 1;
-			bool arrayDirty : 1;
-			bool errorFlagged : 1;
-		};
-
 	public:
 	public:
 		RenderBeast();
 		RenderBeast();
 		~RenderBeast() { }
 		~RenderBeast() { }
@@ -240,7 +229,7 @@ namespace bs
 		Vector<Sphere> mPointLightWorldBounds;
 		Vector<Sphere> mPointLightWorldBounds;
 		Vector<Sphere> mSpotLightWorldBounds;
 		Vector<Sphere> mSpotLightWorldBounds;
 
 
-		Vector<ReflProbeInfo> mReflProbes;
+		Vector<RendererReflectionProbe> mReflProbes;
 		Vector<Sphere> mReflProbeWorldBounds;
 		Vector<Sphere> mReflProbeWorldBounds;
 		Vector<bool> mCubemapArrayUsedSlots;
 		Vector<bool> mCubemapArrayUsedSlots;
 		SPtr<Texture> mCubemapArrayTex;
 		SPtr<Texture> mCubemapArrayTex;
@@ -254,6 +243,7 @@ namespace bs
 		SkyboxMat<true>* mSkyboxSolidColorMat;
 		SkyboxMat<true>* mSkyboxSolidColorMat;
 
 
 		GPULightData* mGPULightData;
 		GPULightData* mGPULightData;
+		GPUReflProbeData* mGPUReflProbeData;
 		LightGrid* mLightGrid;
 		LightGrid* mLightGrid;
 
 
 		ObjectRenderer* mObjectRenderer;
 		ObjectRenderer* mObjectRenderer;
@@ -265,6 +255,9 @@ namespace bs
 		// Helpers to avoid memory allocations
 		// Helpers to avoid memory allocations
 		Vector<LightData> mLightDataTemp;
 		Vector<LightData> mLightDataTemp;
 		Vector<bool> mLightVisibilityTemp;
 		Vector<bool> mLightVisibilityTemp;
+
+		Vector<ReflProbeData> mReflProbeDataTemp;
+		Vector<bool> mReflProbeVisibilityTemp;
 	};
 	};
 
 
 	/** @} */
 	/** @} */

+ 79 - 0
Source/RenderBeast/Source/BsReflectionProbeSampling.cpp

@@ -0,0 +1,79 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsReflectionProbeSampling.h"
+#include "BsMaterial.h"
+#include "BsShader.h"
+#include "BsRenderBeast.h"
+#include "BsGpuBuffer.h"
+#include "BsReflectionProbe.h"
+#include "BsReflectionCubemapCache.h"
+
+namespace bs { namespace ct
+{
+	static const UINT32 BUFFER_INCREMENT = 16 * sizeof(ReflProbeData);
+
+	ReflProbeParamsParamDef gReflProbeParamsParamDef;
+
+	GPUReflProbeData::GPUReflProbeData()
+		:mNumProbes(0)
+	{ }
+
+	void GPUReflProbeData::setProbes(const Vector<ReflProbeData>& probeData, UINT32 numProbes)
+	{
+		mNumProbes = numProbes;
+
+		UINT32 size = numProbes * sizeof(ReflProbeData);
+		UINT32 curBufferSize;
+
+		if (mProbeBuffer != nullptr)
+			curBufferSize = mProbeBuffer->getSize();
+		else
+			curBufferSize = 0;
+
+		if (size > curBufferSize || curBufferSize == 0)
+		{
+			// Allocate at least one block even if no probes, to avoid issues with null buffers
+			UINT32 bufferSize = std::max(1, Math::ceilToInt(size / (float)BUFFER_INCREMENT)) * BUFFER_INCREMENT;
+
+			GPU_BUFFER_DESC bufferDesc;
+			bufferDesc.type = GBT_STRUCTURED;
+			bufferDesc.elementCount = bufferSize / sizeof(ReflProbeData);
+			bufferDesc.elementSize = sizeof(ReflProbeData);
+			bufferDesc.format = BF_UNKNOWN;
+
+			mProbeBuffer = GpuBuffer::create(bufferDesc);
+		}
+
+		if (size > 0)
+			mProbeBuffer->writeData(0, size, probeData.data(), BWT_DISCARD);
+	}
+
+	RendererReflectionProbe::RendererReflectionProbe(ReflectionProbe* probe)
+		:probe(probe)
+	{
+		arrayIdx = -1;
+		texture = probe->getCustomTexture();
+		customTexture = texture != nullptr;
+		textureDirty = ReflectionCubemapCache::instance().isDirty(probe->getUUID());
+		arrayDirty = true;
+		errorFlagged = false;
+	}
+
+	void RendererReflectionProbe::getParameters(ReflProbeData& output) const
+	{
+		output.type = probe->getType() == ReflectionProbeType::Sphere ? 0 
+			: probe->getType() == ReflectionProbeType::Box ? 1 : 2;
+		
+		output.position = probe->getPosition();
+		output.boxExtents = probe->getExtents();
+
+		if (probe->getType() == ReflectionProbeType::Sphere)
+			output.radius = probe->getRadius();
+		else
+			output.radius = output.boxExtents.length();
+
+		output.transitionDistance = probe->getTransitionDistance();
+		output.cubemapIdx = arrayIdx;
+		output.invBoxTransform.setInverseTRS(output.position, probe->getRotation(), output.boxExtents);
+	}
+}}

+ 38 - 14
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -42,9 +42,17 @@ using namespace std::placeholders;
 namespace bs { namespace ct
 namespace bs { namespace ct
 {
 {
 	RenderBeast::RenderBeast()
 	RenderBeast::RenderBeast()
-		: mDefaultMaterial(nullptr), mTiledDeferredLightingMats(), mFlatFramebufferToTextureMat(nullptr)
-		, mSkyboxMat(nullptr), mSkyboxSolidColorMat(nullptr), mGPULightData(nullptr), mLightGrid(nullptr)
-		, mObjectRenderer(nullptr), mOptions(bs_shared_ptr_new<RenderBeastOptions>()), mOptionsDirty(true)
+		: mDefaultMaterial(nullptr)
+		, mTiledDeferredLightingMats()
+		, mFlatFramebufferToTextureMat(nullptr)
+		, mSkyboxMat(nullptr)
+		, mSkyboxSolidColorMat(nullptr)
+		, mGPULightData(nullptr)
+		, mGPUReflProbeData(nullptr)
+		, mLightGrid(nullptr)
+		, mObjectRenderer(nullptr)
+		, mOptions(bs_shared_ptr_new<RenderBeastOptions>())
+		, mOptionsDirty(true)
 	{ }
 	{ }
 
 
 	const StringID& RenderBeast::getName() const
 	const StringID& RenderBeast::getName() const
@@ -86,6 +94,7 @@ namespace bs { namespace ct
 		mTiledDeferredLightingMats[3] = bs_new<TTiledDeferredLightingMat<8>>();
 		mTiledDeferredLightingMats[3] = bs_new<TTiledDeferredLightingMat<8>>();
 
 
 		mGPULightData = bs_new<GPULightData>();
 		mGPULightData = bs_new<GPULightData>();
+		mGPUReflProbeData = bs_new<GPUReflProbeData>();
 		mLightGrid = bs_new<LightGrid>();
 		mLightGrid = bs_new<LightGrid>();
 
 
 		GpuResourcePool::startUp();
 		GpuResourcePool::startUp();
@@ -117,6 +126,7 @@ namespace bs { namespace ct
 		bs_delete(mSkyboxMat);
 		bs_delete(mSkyboxMat);
 		bs_delete(mSkyboxSolidColorMat);
 		bs_delete(mSkyboxSolidColorMat);
 		bs_delete(mGPULightData);
 		bs_delete(mGPULightData);
+		bs_delete(mGPUReflProbeData);
 		bs_delete(mLightGrid);
 		bs_delete(mLightGrid);
 		bs_delete(mFlatFramebufferToTextureMat);
 		bs_delete(mFlatFramebufferToTextureMat);
 
 
@@ -455,15 +465,8 @@ namespace bs { namespace ct
 		UINT32 probeId = (UINT32)mReflProbes.size();
 		UINT32 probeId = (UINT32)mReflProbes.size();
 		probe->setRendererId(probeId);
 		probe->setRendererId(probeId);
 
 
-		mReflProbes.push_back(ReflProbeInfo());
-		ReflProbeInfo& probeInfo = mReflProbes.back();
-		probeInfo.probe = probe;
-		probeInfo.arrayIdx = -1;
-		probeInfo.texture = probe->getCustomTexture();
-		probeInfo.customTexture = probeInfo.texture != nullptr;
-		probeInfo.textureDirty = ReflectionCubemapCache::instance().isDirty(probe->getUUID());
-		probeInfo.arrayDirty = true;
-		probeInfo.errorFlagged = false;
+		mReflProbes.push_back(RendererReflectionProbe(probe));
+		RendererReflectionProbe& probeInfo = mReflProbes.back();
 
 
 		mReflProbeWorldBounds.push_back(probe->getBounds());
 		mReflProbeWorldBounds.push_back(probe->getBounds());
 
 
@@ -496,7 +499,7 @@ namespace bs { namespace ct
 		UINT32 probeId = probe->getRendererId();
 		UINT32 probeId = probe->getRendererId();
 		mReflProbeWorldBounds[probeId] = probe->getBounds();
 		mReflProbeWorldBounds[probeId] = probe->getBounds();
 
 
-		ReflProbeInfo& probeInfo = mReflProbes[probeId];
+		RendererReflectionProbe& probeInfo = mReflProbes[probeId];
 		probeInfo.arrayDirty = true;
 		probeInfo.arrayDirty = true;
 
 
 		if (!probeInfo.customTexture)
 		if (!probeInfo.customTexture)
@@ -844,6 +847,27 @@ namespace bs { namespace ct
 		mLightDataTemp.clear();
 		mLightDataTemp.clear();
 		mLightVisibilityTemp.clear();
 		mLightVisibilityTemp.clear();
 
 
+		// Gemerate reflection probes and their GPU buffers
+		UINT32 numProbes = (UINT32)mReflProbes.size();
+
+		mReflProbeVisibilityTemp.resize(numProbes, false);
+		for (UINT32 i = 0; i < numViews; i++)
+			views[i]->calculateVisibility(mReflProbeWorldBounds, mReflProbeVisibilityTemp);
+
+		for(UINT32 i = 0; i < numProbes; i++)
+		{
+			if (!mReflProbeVisibilityTemp[i])
+				continue;
+
+			mReflProbeDataTemp.push_back(ReflProbeData());
+			mReflProbes[i].getParameters(mReflProbeDataTemp.back());
+		}
+
+		mGPUReflProbeData->setProbes(mReflProbeDataTemp, numProbes);
+
+		mReflProbeDataTemp.clear();
+		mReflProbeVisibilityTemp.clear();
+
 		// Update various buffers required by each renderable
 		// Update various buffers required by each renderable
 		UINT32 numRenderables = (UINT32)mRenderables.size();
 		UINT32 numRenderables = (UINT32)mRenderables.size();
 		for (UINT32 i = 0; i < numRenderables; i++)
 		for (UINT32 i = 0; i < numRenderables; i++)
@@ -1205,7 +1229,7 @@ namespace bs { namespace ct
 			FrameQueue<UINT32> emptySlots;
 			FrameQueue<UINT32> emptySlots;
 			for (UINT32 i = 0; i < numProbes; i++)
 			for (UINT32 i = 0; i < numProbes; i++)
 			{
 			{
-				ReflProbeInfo& probeInfo = mReflProbes[i];
+				RendererReflectionProbe& probeInfo = mReflProbes[i];
 				if (!probeInfo.customTexture)
 				if (!probeInfo.customTexture)
 				{
 				{
 					if (probeInfo.probe->getType() != ReflectionProbeType::Plane)
 					if (probeInfo.probe->getType() != ReflectionProbeType::Plane)