浏览代码

Functions for creating light probes in a grid pattern, as well as manipulating them

BearishSun 8 年之前
父节点
当前提交
c79c7666f3

+ 36 - 7
Source/BansheeCore/Include/BsLightProbeVolume.h

@@ -7,6 +7,7 @@
 #include "BsAABox.h"
 #include "BsVector3.h"
 #include "BsQuaternion.h"
+#include "BsVectorNI.h"
 
 namespace bs
 {
@@ -137,6 +138,32 @@ namespace bs
 		 */
 		void renderProbes();
 
+		/** 
+		 * Resizes the light probe grid and inserts new light probes, if the new size is larger than previous size.
+		 * New probes are inserted in a grid pattern matching the new size and density parameters. 
+		 * 
+		 * Note that shrinking the volume will not remove light probes. In order to remove probes outside of the new volume
+		 * call clip().
+		 * 
+		 * Resize will not change the positions of current light probes. If you wish to reset all probes to the currently
+		 * set grid position, call reset().
+
+		 * @param[in]	volume		Axis aligned volume to be covered by the light probes.
+		 * @param[in]	cellCount	Number of grid cells to split the volume into. Minimum number of 1, in which case each
+		 *							corner of the volume is represented by a single probe. Higher values subdivide the
+		 *							volume in an uniform way.
+		 */
+		void resize(const AABox& volume, const Vector3I& cellCount = {1, 1, 1});
+
+		/** Removes any probes outside of the current grid volume. */
+		void clip();
+
+		/** 
+		 * Resets all probes to match the original grid pattern. This will reset probe positions, as well as add/remove
+		 * probes as necessary, essentially losing any custom changes to the probes.
+		 */
+		void reset();		
+
 		/**	Retrieves an implementation of the object usable only from the core thread. */
 		SPtr<ct::LightProbeVolume> getCore() const;
 
@@ -144,16 +171,15 @@ namespace bs
 		 * Creates a new light volume with probes aligned in a grid pattern.
 		 * 
 		 * @param[in]	volume		Axis aligned volume to be covered by the light probes.
-		 * @param[in]	density		Density of light probes in each direction. Starting on one side of the volume, a new
-		 *							probe will be added every 1/density meters (per-axis). Note that one probe will be
-		 *							placed at the start and at the end of the volume, regardless of density. This means the
-		 *							smallest volume will have 8 probes.
+		 * @param[in]	cellCount	Number of grid cells to split the volume into. Minimum number of 1, in which case each
+		 *							corner of the volume is represented by a single probe. Higher values subdivide the
+		 *							volume in an uniform way.
 		 */
-		static SPtr<LightProbeVolume> create(const AABox& volume = AABox::UNIT_BOX, const Vector3& density = Vector3::ONE);
+		static SPtr<LightProbeVolume> create(const AABox& volume = AABox::UNIT_BOX, const Vector3I& cellCount = {1, 1, 1});
 	protected:
 		friend class ct::LightProbeVolume;
 
-		LightProbeVolume(const AABox& volume, const Vector3& density);
+		LightProbeVolume(const AABox& volume, const Vector3I& cellCount);
 
 		/** Renders the light probe data on the core thread. */
 		void runRenderProbeTask();
@@ -178,6 +204,9 @@ namespace bs
 
 	private:
 		UnorderedMap<UINT32, ProbeInfo> mProbes;
+		AABox mVolume = AABox::UNIT_BOX;
+		Vector3I mCellCount;
+
 		UINT32 mNextProbeId = 0;
 		SPtr<ct::RendererTask> mRendererTask;
 
@@ -280,4 +309,4 @@ namespace bs
 	}
 
 	/** @} */
-}
+}

+ 2 - 0
Source/BansheeCore/Include/BsLightProbeVolumeRTTI.h

@@ -88,6 +88,8 @@ namespace bs
 		BS_BEGIN_RTTI_MEMBERS
 			BS_RTTI_MEMBER_PLAIN(mPosition, 0)
 			BS_RTTI_MEMBER_PLAIN(mRotation, 1)
+			BS_RTTI_MEMBER_PLAIN(mVolume, 3)
+			BS_RTTI_MEMBER_PLAIN(mCellCount, 4)
 		BS_END_RTTI_MEMBERS
 
 		SavedLightProbeInfo& getProbeInfo(LightProbeVolume* obj)

+ 99 - 4
Source/BansheeCore/Source/BsLightProbeVolume.cpp

@@ -16,11 +16,13 @@ namespace bs
 	{ }
 
 	LightProbeVolume::LightProbeVolume()
+		: mVolume(AABox::UNIT_BOX), mCellCount { 1, 1, 1 }
 	{ }
 
-	LightProbeVolume::LightProbeVolume(const AABox& volume, const Vector3& density)
+	LightProbeVolume::LightProbeVolume(const AABox& volume, const Vector3I& cellCount)
+		:mVolume(volume), mCellCount(cellCount)
 	{
-		// TODO - Generates probes in the grid volume
+		reset();
 	}
 
 	LightProbeVolume::~LightProbeVolume()
@@ -67,6 +69,99 @@ namespace bs
 		return Vector3::ZERO;
 	}
 
+	void LightProbeVolume::resize(const AABox& volume, const Vector3I& cellCount)
+	{
+		UINT32 numProbesX = std::max(1, mCellCount.v[0]) + 1;
+		UINT32 numProbesY = std::max(1, mCellCount.v[1]) + 1;
+		UINT32 numProbesZ = std::max(1, mCellCount.v[2]) + 1;
+
+		Vector3 size = mVolume.getSize();
+		for(UINT32 z = 0; z < numProbesZ; ++z)
+		{
+			for(UINT32 y = 0; y < numProbesY; ++y)
+			{
+				for(UINT32 x = 0; x < numProbesX; ++x)
+				{
+					Vector3 position = mVolume.getMin();
+					position.x += size.x * (x / (float)numProbesX);
+					position.y += size.y * (y / (float)numProbesY);
+					position.z += size.z * (z / (float)numProbesZ);
+
+					if (mVolume.contains(position))
+						continue;
+
+					addProbe(position);
+				}
+			}
+		}
+
+		mVolume = volume;
+		mCellCount = cellCount;
+
+		_markCoreDirty();
+	}
+
+	void LightProbeVolume::reset()
+	{
+		UINT32 numProbesX = std::max(1, mCellCount.v[0]) + 1;
+		UINT32 numProbesY = std::max(1, mCellCount.v[1]) + 1;
+		UINT32 numProbesZ = std::max(1, mCellCount.v[2]) + 1;
+
+		UINT32 numProbes = numProbesX * numProbesY * numProbesZ;
+
+		// Make sure there are adequate number of probes to fill the volume
+		while((UINT32)mProbes.size() < numProbes)
+			addProbe(Vector3::ZERO);
+
+		UINT32 idx = 0;
+		UINT32 rowPitch = numProbesX;
+		UINT32 slicePitch = numProbesX * numProbesY;
+
+		Vector3 size = mVolume.getSize();
+
+		auto iter = mProbes.begin();
+		while (iter != mProbes.end())
+		{
+			UINT32 x = idx % numProbesX;
+			UINT32 y = (idx / rowPitch) % numProbesY;
+			UINT32 z = (idx / slicePitch);
+
+			Vector3 position = mVolume.getMin();
+			position.x += size.x * (x / (float)numProbesX);
+			position.y += size.y * (y / (float)numProbesY);
+			position.z += size.z * (z / (float)numProbesZ);
+
+			iter->second.position = position;
+			iter->second.flags = LightProbeFlags::Clean;
+
+			++idx;
+			++iter;
+
+			if (idx >= numProbes)
+				break;
+		}
+
+		// Set remaining probes to removed state
+		while(iter != mProbes.end())
+		{
+			iter->second.flags = LightProbeFlags::Removed;
+			++iter;
+		}
+
+		_markCoreDirty();
+	}
+
+	void LightProbeVolume::clip()
+	{
+		for (auto& entry : mProbes)
+		{
+			if (!mVolume.contains(entry.second.position))
+				entry.second.flags = LightProbeFlags::Removed;
+		}
+
+		_markCoreDirty();
+	}
+
 	void LightProbeVolume::renderProbe(UINT32 handle)
 	{
 		auto iterFind = mProbes.find(handle);
@@ -160,9 +255,9 @@ namespace bs
 		return std::static_pointer_cast<ct::LightProbeVolume>(mCoreSpecific);
 	}
 
-	SPtr<LightProbeVolume> LightProbeVolume::create(const AABox& volume, const Vector3& density)
+	SPtr<LightProbeVolume> LightProbeVolume::create(const AABox& volume, const Vector3I& cellCount)
 	{
-		LightProbeVolume* probeVolume = new (bs_alloc<LightProbeVolume>()) LightProbeVolume(volume, density);
+		LightProbeVolume* probeVolume = new (bs_alloc<LightProbeVolume>()) LightProbeVolume(volume, cellCount);
 		SPtr<LightProbeVolume> probeVolumePtr = bs_core_ptr<LightProbeVolume>(probeVolume);
 		probeVolumePtr->_setThisPtr(probeVolumePtr);
 		probeVolumePtr->initialize();

+ 9 - 0
Source/BansheeUtility/Include/BsVectorNI.h

@@ -27,6 +27,12 @@ namespace bs
 			memcpy(v, val, sizeof(v));
 		}
 
+		VectorNI(std::initializer_list<INT32> list)
+		{
+			assert(list.size() < N);
+			std::copy(list.begin(), list.end(), v);
+		}
+
 		INT32 operator[] (size_t i) const
 		{
 			assert(i < N);
@@ -69,4 +75,7 @@ namespace bs
 
 	typedef VectorNI<3> Vector3I;
 	typedef VectorNI<4> Vector4I;
+
+	BS_ALLOW_MEMCPY_SERIALIZATION(Vector3I)
+	BS_ALLOW_MEMCPY_SERIALIZATION(Vector4I)
 }