Browse Source

Reflection capture code

BearishSun 9 năm trước cách đây
mục cha
commit
f3c0d2e377

+ 0 - 11
Source/BansheeCore/Include/BsCamera.h

@@ -36,17 +36,6 @@ namespace bs
 		PT_PERSPECTIVE /**< Projection type that emulates human vision. Objects farther away appear smaller. */
     };
 
-	/**	Clip planes that form the camera frustum (visible area). */
-    enum FrustumPlane
-    {
-        FRUSTUM_PLANE_NEAR = 0,
-        FRUSTUM_PLANE_FAR = 1,
-        FRUSTUM_PLANE_LEFT = 2,
-        FRUSTUM_PLANE_RIGHT = 3,
-        FRUSTUM_PLANE_TOP = 4,
-        FRUSTUM_PLANE_BOTTOM = 5
-    };
-
 	/**	Flags that describe a camera. */
 	enum class CameraFlag
 	{

+ 6 - 6
Source/BansheeCore/Include/BsPixelData.h

@@ -138,12 +138,12 @@ namespace bs
 	/** A list of cubemap faces. */
 	enum CubemapFace
 	{
-		PositiveX,
-		NegativeX,
-		PositiveY,
-		NegativeY,
-		PositiveZ,
-		NegativeZ
+		CF_PositiveX,
+		CF_NegativeX,
+		CF_PositiveY,
+		CF_NegativeY,
+		CF_PositiveZ,
+		CF_NegativeZ
 	};
 
 	/**

+ 1 - 40
Source/BansheeCore/Source/BsCamera.cpp

@@ -335,46 +335,7 @@ namespace bs
 
 		if (mRecalcFrustumPlanes)
 		{
-			Vector<Plane> frustumPlanes(6);
-			Matrix4 combo = mProjMatrix;
-
-			frustumPlanes[FRUSTUM_PLANE_LEFT].normal.x = combo[3][0] + combo[0][0];
-			frustumPlanes[FRUSTUM_PLANE_LEFT].normal.y = combo[3][1] + combo[0][1];
-			frustumPlanes[FRUSTUM_PLANE_LEFT].normal.z = combo[3][2] + combo[0][2];
-			frustumPlanes[FRUSTUM_PLANE_LEFT].d = combo[3][3] + combo[0][3];
-
-			frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.x = combo[3][0] - combo[0][0];
-			frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.y = combo[3][1] - combo[0][1];
-			frustumPlanes[FRUSTUM_PLANE_RIGHT].normal.z = combo[3][2] - combo[0][2];
-			frustumPlanes[FRUSTUM_PLANE_RIGHT].d = combo[3][3] - combo[0][3];
-
-			frustumPlanes[FRUSTUM_PLANE_TOP].normal.x = combo[3][0] - combo[1][0];
-			frustumPlanes[FRUSTUM_PLANE_TOP].normal.y = combo[3][1] - combo[1][1];
-			frustumPlanes[FRUSTUM_PLANE_TOP].normal.z = combo[3][2] - combo[1][2];
-			frustumPlanes[FRUSTUM_PLANE_TOP].d = combo[3][3] - combo[1][3];
-
-			frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.x = combo[3][0] + combo[1][0];
-			frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.y = combo[3][1] + combo[1][1];
-			frustumPlanes[FRUSTUM_PLANE_BOTTOM].normal.z = combo[3][2] + combo[1][2];
-			frustumPlanes[FRUSTUM_PLANE_BOTTOM].d = combo[3][3] + combo[1][3];
-
-			frustumPlanes[FRUSTUM_PLANE_NEAR].normal.x = combo[3][0] + combo[2][0];
-			frustumPlanes[FRUSTUM_PLANE_NEAR].normal.y = combo[3][1] + combo[2][1];
-			frustumPlanes[FRUSTUM_PLANE_NEAR].normal.z = combo[3][2] + combo[2][2];
-			frustumPlanes[FRUSTUM_PLANE_NEAR].d = combo[3][3] + combo[2][3];
-
-			frustumPlanes[FRUSTUM_PLANE_FAR].normal.x = combo[3][0] - combo[2][0];
-			frustumPlanes[FRUSTUM_PLANE_FAR].normal.y = combo[3][1] - combo[2][1];
-			frustumPlanes[FRUSTUM_PLANE_FAR].normal.z = combo[3][2] - combo[2][2];
-			frustumPlanes[FRUSTUM_PLANE_FAR].d = combo[3][3] - combo[2][3];
-
-			for (UINT32 i = 0; i < 6; i++)
-			{
-				float length = frustumPlanes[i].normal.normalize();
-				frustumPlanes[i].d /= -length;
-			}
-
-			mFrustum = ConvexVolume(frustumPlanes);
+			mFrustum = ConvexVolume(mProjMatrix);
 			mRecalcFrustumPlanes = false;
 		}
 	}

+ 3 - 0
Source/BansheeUtility/Include/BsConvexVolume.h

@@ -18,6 +18,9 @@ namespace bs
 		ConvexVolume() {}
 		ConvexVolume(const Vector<Plane>& planes);
 
+		/** Creates frustum planes from the provided projection matrix. */
+		ConvexVolume(const Matrix4& projectionMatrix);
+
 		/**
 		 * Checks does the volume intersects the provided axis aligned box.
 		 * This will return true if the box is fully inside the volume.

+ 2 - 2
Source/BansheeUtility/Include/BsMatrix4.h

@@ -436,7 +436,7 @@ namespace bs
         }
 
 		/** Creates a view matrix and applies optional reflection. */
-		void makeView(const Vector3& position, const Quaternion& orientation, const Matrix4* reflectMatrix = nullptr);
+		void makeView(const Vector3& position, const Quaternion& orientation);
 
 		/** Creates an ortographic projection matrix. */
 		void makeProjectionOrtho(float left, float right, float top, float bottom, float near, float far);
@@ -457,7 +457,7 @@ namespace bs
 		static Matrix4 projectionPerspective(const Degree& horzFOV, float aspect, float near, float far);
 
 		/** Creates a view matrix and applies optional reflection. */
-		static Matrix4 view(const Vector3& position, const Quaternion& orientation, const Matrix4* reflectMatrix = nullptr);
+		static Matrix4 view(const Vector3& position, const Quaternion& orientation);
 
         /**
          * Creates a matrix from translation, rotation and scale. 

+ 54 - 0
Source/BansheeUtility/Source/BsConvexVolume.cpp

@@ -8,10 +8,64 @@
 
 namespace bs
 {
+	/**	Clip planes that form the camera frustum (visible area). */
+	enum FrustumPlane
+	{
+		FRUSTUM_PLANE_NEAR = 0,
+		FRUSTUM_PLANE_FAR = 1,
+		FRUSTUM_PLANE_LEFT = 2,
+		FRUSTUM_PLANE_RIGHT = 3,
+		FRUSTUM_PLANE_TOP = 4,
+		FRUSTUM_PLANE_BOTTOM = 5
+	};
+
 	ConvexVolume::ConvexVolume(const Vector<Plane>& planes)
 		:mPlanes(planes)
 	{ }
 
+	ConvexVolume::ConvexVolume(const Matrix4& projectionMatrix)
+	{
+		mPlanes.resize(6);
+
+		const Matrix4& proj = projectionMatrix;
+
+		mPlanes[FRUSTUM_PLANE_LEFT].normal.x = proj[3][0] + proj[0][0];
+		mPlanes[FRUSTUM_PLANE_LEFT].normal.y = proj[3][1] + proj[0][1];
+		mPlanes[FRUSTUM_PLANE_LEFT].normal.z = proj[3][2] + proj[0][2];
+		mPlanes[FRUSTUM_PLANE_LEFT].d = proj[3][3] + proj[0][3];
+
+		mPlanes[FRUSTUM_PLANE_RIGHT].normal.x = proj[3][0] - proj[0][0];
+		mPlanes[FRUSTUM_PLANE_RIGHT].normal.y = proj[3][1] - proj[0][1];
+		mPlanes[FRUSTUM_PLANE_RIGHT].normal.z = proj[3][2] - proj[0][2];
+		mPlanes[FRUSTUM_PLANE_RIGHT].d = proj[3][3] - proj[0][3];
+
+		mPlanes[FRUSTUM_PLANE_TOP].normal.x = proj[3][0] - proj[1][0];
+		mPlanes[FRUSTUM_PLANE_TOP].normal.y = proj[3][1] - proj[1][1];
+		mPlanes[FRUSTUM_PLANE_TOP].normal.z = proj[3][2] - proj[1][2];
+		mPlanes[FRUSTUM_PLANE_TOP].d = proj[3][3] - proj[1][3];
+
+		mPlanes[FRUSTUM_PLANE_BOTTOM].normal.x = proj[3][0] + proj[1][0];
+		mPlanes[FRUSTUM_PLANE_BOTTOM].normal.y = proj[3][1] + proj[1][1];
+		mPlanes[FRUSTUM_PLANE_BOTTOM].normal.z = proj[3][2] + proj[1][2];
+		mPlanes[FRUSTUM_PLANE_BOTTOM].d = proj[3][3] + proj[1][3];
+
+		mPlanes[FRUSTUM_PLANE_NEAR].normal.x = proj[3][0] + proj[2][0];
+		mPlanes[FRUSTUM_PLANE_NEAR].normal.y = proj[3][1] + proj[2][1];
+		mPlanes[FRUSTUM_PLANE_NEAR].normal.z = proj[3][2] + proj[2][2];
+		mPlanes[FRUSTUM_PLANE_NEAR].d = proj[3][3] + proj[2][3];
+
+		mPlanes[FRUSTUM_PLANE_FAR].normal.x = proj[3][0] - proj[2][0];
+		mPlanes[FRUSTUM_PLANE_FAR].normal.y = proj[3][1] - proj[2][1];
+		mPlanes[FRUSTUM_PLANE_FAR].normal.z = proj[3][2] - proj[2][2];
+		mPlanes[FRUSTUM_PLANE_FAR].d = proj[3][3] - proj[2][3];
+
+		for (UINT32 i = 0; i < 6; i++)
+		{
+			float length = mPlanes[i].normal.normalize();
+			mPlanes[i].d /= -length;
+		}
+	}
+
 	bool ConvexVolume::intersects(const AABox& box) const
 	{
 		Vector3 center = box.getCenter();

+ 3 - 9
Source/BansheeUtility/Source/BsMatrix4.cpp

@@ -227,7 +227,7 @@ namespace bs
 		position = Vector3(m[0][3], m[1][3], m[2][3]);
 	}
 
-	void Matrix4::makeView(const Vector3& position, const Quaternion& orientation, const Matrix4* reflectMatrix)
+	void Matrix4::makeView(const Vector3& position, const Quaternion& orientation)
 	{
 		// View matrix is:
 		//
@@ -251,12 +251,6 @@ namespace bs
 		m[0][3] = trans.x;
 		m[1][3] = trans.y;
 		m[2][3] = trans.z;
-
-		// Deal with reflections
-		if (reflectMatrix)
-		{
-			*this = (*this) * (*reflectMatrix);
-		}
 	}
 
 	void Matrix4::makeProjectionOrtho(float left, float right, float top,
@@ -384,10 +378,10 @@ namespace bs
 		return mat;
     }
 
-	Matrix4 Matrix4::view(const Vector3& position, const Quaternion& orientation, const Matrix4* reflectMatrix)
+	Matrix4 Matrix4::view(const Vector3& position, const Quaternion& orientation)
     {
 		Matrix4 mat;
-		mat.makeView(position, orientation, reflectMatrix);
+		mat.makeView(position, orientation);
 
 		return mat;
     }

+ 9 - 0
Source/RenderBeast/Include/BsRenderBeast.h

@@ -162,6 +162,15 @@ namespace bs
 		 */
 		void renderElement(const BeastRenderableElement& element, UINT32 passIdx, bool bindPass, const Matrix4& viewProj);
 
+		/** 
+		 * Captures the scene at the specified location into a cubemap. 
+		 * 
+		 * @param[in]	position	Position to capture the scene at.
+		 * @param[in]	hdr			If true scene will be captured in a format that supports high dynamic range.
+		 * @param[in]	size		Cubemap face width/height in pixels.
+		 */
+		SPtr<Texture> captureSceneCubeMap(const Vector3& position, bool hdr, UINT32 size);
+
 		/**	Creates data used by the renderer on the core thread. */
 		void initializeCore();
 

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

@@ -172,7 +172,7 @@ namespace bs { namespace ct
 		 * @param[in]	renderables			A set of renderable objects to iterate over and determine visibility for.
 		 * @param[in]	renderableBounds	A set of world bounds for the provided renderable objects. Must be the same size
 		 *									as the @p renderables array.
-		 * @param[in]	visibility			Output parameter that will have the true bit set for any visible renderable
+		 * @param[out]	visibility			Output parameter that will have the true bit set for any visible renderable
 		 *									object. If the bit for an object is already set to true, the method will never
 		 *									change it to false which allows the same bitfield to be provided to multiple
 		 *									renderer views. Must be the same size as the @p renderables array.
@@ -181,7 +181,7 @@ namespace bs { namespace ct
 		 *									retrieved by calling getVisibilityMask().
 		 */
 		void determineVisible(const Vector<RendererObject*>& renderables, const Vector<Bounds>& renderableBounds, 
-			Vector<bool>& visibility);
+			Vector<bool>* visibility = nullptr);
 
 		/** Returns the visibility mask calculated with the last call to determineVisible(). */
 		const Vector<bool>& getVisibilityMask() const { return mVisibility; }

+ 125 - 1
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -626,7 +626,7 @@ namespace bs { namespace ct
 		mVisibility.assign(mVisibility.size(), false);
 
 		for (auto& entry : mCameras)
-			entry.second->determineVisible(mRenderables, mWorldBounds, mVisibility);
+			entry.second->determineVisible(mRenderables, mWorldBounds, &mVisibility);
 
 		// Retrieve animation data
 		AnimationManager::instance().waitUntilComplete();
@@ -977,6 +977,130 @@ namespace bs { namespace ct
 				element.morphVertexDeclaration);
 	}
 
+	SPtr<Texture> RenderBeast::captureSceneCubeMap(const Vector3& position, bool hdr, UINT32 size)
+	{
+		TEXTURE_DESC cubeMapDesc;
+		cubeMapDesc.type = TEX_TYPE_CUBE_MAP;
+		cubeMapDesc.format = hdr ? PF_FLOAT16_RGBA : PF_R8G8B8A8;
+		cubeMapDesc.width = size;
+		cubeMapDesc.height = size;
+		cubeMapDesc.usage = TU_RENDERTARGET;
+
+		SPtr<Texture> cubemap = Texture::create(cubeMapDesc);
+
+		Matrix4 projTransform = Matrix4::projectionPerspective(Degree(90.0f), 1.0f, 0.05f, 1000.0f);
+		ConvexVolume localFrustum(projTransform);
+		RenderAPI::instance().convertProjectionMatrix(projTransform, projTransform);
+
+		RENDERER_VIEW_DESC viewDesc;
+		viewDesc.target.clearFlags = FBT_COLOR | FBT_DEPTH;
+		viewDesc.target.clearColor = Color::Black;
+		viewDesc.target.clearDepthValue = 1.0f;
+		viewDesc.target.clearStencilValue = 0;
+
+		viewDesc.target.nrmViewRect = Rect2(0, 0, 1.0f, 1.0f);
+		viewDesc.target.viewRect = Rect2I(0, 0, size, size);
+		viewDesc.target.targetWidth = size;
+		viewDesc.target.targetHeight = size;
+		viewDesc.target.numSamples = 1;
+
+		viewDesc.isOverlay = false;
+		viewDesc.isHDR = hdr;
+		viewDesc.triggerCallbacks = false;
+		viewDesc.runPostProcessing = false;
+
+		viewDesc.visibleLayers = 0xFFFFFFFFFFFFFFFF;
+		viewDesc.nearPlane = 0.5f;
+
+		viewDesc.viewOrigin = position;
+		viewDesc.projTransform = projTransform;
+
+		viewDesc.stateReduction = mCoreOptions->stateReductionMode;
+		viewDesc.sceneCamera = nullptr;
+
+		// Note: Find a camera to receive skybox from. Skybox should probably be a global property instead of a per-camera
+		// one.
+		for(auto& entry : mRenderTargets)
+		{
+			for(auto& camera : entry.cameras)
+			{
+				if (camera->getSkybox() != nullptr)
+				{
+					viewDesc.skyboxTexture = camera->getSkybox();
+					break;
+				}
+			}
+		}
+
+		Matrix4 viewOffsetMat = Matrix4::translation(-position);
+
+		for(UINT32 i = 0; i < 6; i++)
+		{
+			// Calculate view matrix
+			Vector3 forward;
+			Vector3 up = Vector3::UNIT_Y;
+
+			switch(i)
+			{
+			case CF_PositiveX:
+				forward = Vector3::UNIT_X;
+				break;
+			case CF_NegativeX:
+				forward = -Vector3::UNIT_X;
+				break;
+			case CF_PositiveY:
+				forward = Vector3::UNIT_Y;
+				up = -Vector3::UNIT_Z;
+				break;
+			case CF_NegativeY:
+				forward = Vector3::UNIT_X;
+				up = Vector3::UNIT_Z;
+				break;
+			case CF_PositiveZ:
+				forward = Vector3::UNIT_Z;
+				break;
+			case CF_NegativeZ:
+				forward = -Vector3::UNIT_Z;
+				break;
+			}
+
+			Vector3 right = Vector3::cross(up, forward);
+			Matrix3 viewRotationMat = Matrix3(right, up, forward);
+
+			viewDesc.viewDirection = forward;
+			viewDesc.viewTransform = viewOffsetMat * Matrix4(viewRotationMat);
+
+			// Calculate world frustum for culling
+			const Vector<Plane>& frustumPlanes = localFrustum.getPlanes();
+			Matrix4 worldMatrix = viewDesc.viewTransform.transpose();
+
+			Vector<Plane> worldPlanes(frustumPlanes.size());
+			UINT32 j = 0;
+			for (auto& plane : frustumPlanes)
+			{
+				worldPlanes[j] = worldMatrix.multiplyAffine(plane);
+				j++;
+			}
+
+			viewDesc.cullFrustum = ConvexVolume(worldPlanes);
+
+			// Set up face render target
+			RENDER_TEXTURE_DESC cubeFaceRTDesc;
+			cubeFaceRTDesc.colorSurfaces[0].texture = cubemap;
+			cubeFaceRTDesc.colorSurfaces[0].face = i;
+			cubeFaceRTDesc.colorSurfaces[0].numFaces = 1;
+			
+			viewDesc.target.target = RenderTexture::create(cubeFaceRTDesc);
+
+			RendererCamera view(viewDesc);
+
+			view.determineVisible(mRenderables, mWorldBounds);
+			render(&view, 0.0f);
+		}
+
+		return cubemap;
+	}
+
 	void RenderBeast::refreshSamplerOverrides(bool force)
 	{
 		bool anyDirty = false;

+ 11 - 2
Source/RenderBeast/Source/BsRendererCamera.cpp

@@ -120,7 +120,7 @@ namespace bs { namespace ct
 	}
 
 	void RendererCamera::determineVisible(const Vector<RendererObject*>& renderables, const Vector<Bounds>& renderableBounds,
-		Vector<bool>& visibility)
+		Vector<bool>* visibility)
 	{
 		mVisibility.clear();
 		mVisibility.resize(renderables.size(), false);
@@ -151,7 +151,6 @@ namespace bs { namespace ct
 
 				if (worldFrustum.intersects(boundingBox))
 				{
-					visibility[i] = true;
 					mVisibility[i] = true;
 
 					float distanceToCamera = (mViewDesc.viewOrigin - boundingBox.getCenter()).length();
@@ -170,6 +169,16 @@ namespace bs { namespace ct
 			}
 		}
 
+		if(visibility != nullptr)
+		{
+			for (UINT32 i = 0; i < (UINT32)renderables.size(); i++)
+			{
+				bool visible = (*visibility)[i];
+
+				(*visibility)[i] = visible || mVisibility[i];
+			}
+		}
+
 		mOpaqueQueue->sort();
 		mTransparentQueue->sort();
 	}