Browse Source

Transparent rendering path now functional using clustered rendering without depth pre-pass requirement. Same path can also be used for normal opaque object rendering if needed.

BearishSun 8 years ago
parent
commit
c530c1795f

+ 9 - 8
Data/Raw/Engine/Includes/LightGridCommon.bslinc

@@ -18,9 +18,9 @@ Technique : base("LightGridCommon") =
 				uint2 gGridPixelSize;
 			}
 			
-			float convertToDeviceZ(float viewZ)
+			float convertToNDCZ(float viewZ)
 			{
-				return -gDeviceZToWorldZ.y + (gDeviceZToWorldZ.x / viewZ);
+				return -gNDCZToWorldZ.y + (gNDCZToWorldZ.x / viewZ);
 			}
 			
 			float calcViewZFromCellZ(uint cellZ)
@@ -43,10 +43,6 @@ Technique : base("LightGridCommon") =
 			
 			uint calcCellIdx(uint2 pixelPos, float deviceZ)
 			{
-				// MARK: API_SPECIFIC
-				// Grid origin is bottom left but DirectX pixel position origin is top left
-				pixelPos.y = gViewportRectangle.w - pixelPos.y;
-			
 				// Note: Use bitshift to divide since gGridPixelSize will be a power of 2
 				uint2 cellXY = pixelPos / gGridPixelSize;
 				uint cellZ = calcCellZFromViewZ(convertFromDeviceZ(deviceZ));
@@ -78,9 +74,9 @@ Technique : base("LightGridCommon") =
 				uvec2 gGridPixelSize;
 			};
 			
-			float convertToDeviceZ(float viewZ)
+			float convertToNDCZ(float viewZ)
 			{
-				return -gDeviceZToWorldZ.y + (gDeviceZToWorldZ.x / viewZ);
+				return -gNDCZToWorldZ.y + (gNDCZToWorldZ.x / viewZ);
 			}
 			
 			float calcViewZFromCellZ(uint cellZ)
@@ -103,6 +99,11 @@ Technique : base("LightGridCommon") =
 			
 			int calcCellIdx(uvec2 pixelPos, float deviceZ)
 			{
+				// OpenGL uses lower left for window space origin, we use upper-left
+				#ifdef OPENGL
+					pixelPos.y = gViewportRectangle.w - pixelPos.y;
+				#endif
+			
 				// Note: Use bitshift to divide since gGridPixelSize will be a power of 2
 				uvec2 cellXY = pixelPos / gGridPixelSize;
 				uint cellZ = calcCellZFromViewZ(convertFromDeviceZ(deviceZ));

+ 4 - 0
Data/Raw/Engine/Includes/PerCameraData.bslinc

@@ -52,11 +52,13 @@ Technique : base("PerCameraData") =
 				float4x4 gMatInvViewProj;
 				float4x4 gMatScreenToWorld;
 				float2 	 gDeviceZToWorldZ;
+				float2	 gNDCZToWorldZ;
 				float2	 gNearFar;
 				int4 	 gViewportRectangle;
 				float4 	 gClipToUVScaleOffset;				
 			}
 			
+			/** Converts Z value in range [0,1] into Z value in view space. */
 			float convertFromDeviceZ(float deviceZ)
 			{
 				return (1.0f / (deviceZ + gDeviceZToWorldZ.y)) * gDeviceZToWorldZ.x;
@@ -84,11 +86,13 @@ Technique : base("PerCameraData") =
 				mat4 gMatInvViewProj;
 				mat4 gMatScreenToWorld;
 				vec2 gDeviceZToWorldZ;
+				vec2 gNDCZToWorldZ;
 				vec2 gNearFar;
 				ivec4 gViewportRectangle;
 				vec4 gClipToUVScaleOffset;				
 			};
 			
+			/** Converts Z value in range [0,1] into Z value in view space. */
 			float convertFromDeviceZ(float deviceZ)
 			{
 				return (1.0f / (deviceZ + gDeviceZToWorldZ.y)) * gDeviceZToWorldZ.x;	

+ 8 - 6
Data/Raw/Engine/Shaders/LightGridLLCreation.bsl

@@ -41,7 +41,8 @@ Technique
 				ndcMax.xy = (cellIdx.xy + 1) * a - float2(1.0f, 1.0f);
 			
 				// Flip Y depending on render API, depending if Y in NDC is facing up or down
-				float flipY = sign(gMatProj[1][1]);
+				// (We negate the value because we want NDC with Y flipped, so origin is top left)
+				float flipY = -sign(gMatProj[1][1]);
 				ndcMin.y *= flipY;
 				ndcMax.y *= flipY;
 			
@@ -49,8 +50,8 @@ Technique
 				float viewZMin = calcViewZFromCellZ(cellIdx.z + 1);
 				float viewZMax = calcViewZFromCellZ(cellIdx.z);
 			
-				ndcMin.z = convertToDeviceZ(viewZMax);
-				ndcMax.z = convertToDeviceZ(viewZMin);
+				ndcMin.z = convertToNDCZ(viewZMax);
+				ndcMax.z = convertToNDCZ(viewZMin);
 			
 				float4 corner[8];
 				// Near
@@ -170,7 +171,8 @@ Technique
 				ndcMax.xy = (cellIdx.xy + 1) * a - vec2(1.0f, 1.0f);
 			
 				// Flip Y depending on render API, depending if Y in NDC is facing up or down
-				float flipY = sign(gMatProj[1][1]);
+				// (We negate the value because we want NDC with Y flipped, so origin is top left)
+				float flipY = -sign(gMatProj[1][1]);
 				ndcMin.y *= flipY;
 				ndcMax.y *= flipY;
 			
@@ -178,8 +180,8 @@ Technique
 				float viewZMin = calcViewZFromCellZ(cellIdx.z + 1);
 				float viewZMax = calcViewZFromCellZ(cellIdx.z);
 			
-				ndcMin.z = convertToDeviceZ(viewZMin);
-				ndcMax.z = convertToDeviceZ(viewZMax);
+				ndcMin.z = convertToNDCZ(viewZMax);
+				ndcMax.z = convertToNDCZ(viewZMin);
 							
 				vec4 corner[8];
 				// Near

+ 11 - 5
Source/BansheeGLRenderAPI/Source/GLSL/src/BsGLSLGpuProgram.cpp

@@ -86,8 +86,8 @@ namespace bs { namespace ct
 
 	void GLSLGpuProgram::initialize()
 	{
-		static const char GLSL_VERSION_LINE[] = "#version 440\n";
-
+		static const char* EXTRA_LINES[] = { "#version 440\n", "#define OPENGL\n" };
+		
 		if (!isSupported())
 		{
 			mIsCompiled = false;
@@ -132,10 +132,16 @@ namespace bs { namespace ct
 		{
 			Vector<GLchar*> lines;
 
-			GLchar* firstLineData = (GLchar*)bs_stack_alloc(sizeof(GLSL_VERSION_LINE));
-			memcpy(firstLineData, GLSL_VERSION_LINE, sizeof(GLSL_VERSION_LINE));
+			UINT32 numExtraLines = sizeof(EXTRA_LINES) / sizeof(EXTRA_LINES[0]);
+			for(UINT32 i = 0; i < numExtraLines; i++)
+			{
+				UINT32 length = strlen(EXTRA_LINES[i]) + 1;
+
+				GLchar* extraLineData = (GLchar*)bs_stack_alloc(length);
+				memcpy(extraLineData, EXTRA_LINES[i], length);
 
-			lines.push_back(firstLineData);
+				lines.push_back(extraLineData);
+			}
 
 			UINT32 lineLength = 0;
 			for (UINT32 i = 0; i < source.size(); i++)

+ 1 - 1
Source/BansheeVulkanRenderAPI/Include/BsVulkanRenderAPI.h

@@ -92,7 +92,7 @@ namespace bs { namespace ct
 		/** @copydoc RenderAPI::addCommands() */
 		void addCommands(const SPtr<CommandBuffer>& commandBuffer, const SPtr<CommandBuffer>& secondary) override;
 
-		/** @copydoc RenderAPI::executeCommands() */
+		/** @copydoc RenderAPI::submitCommandBuffer() */
 		void submitCommandBuffer(const SPtr<CommandBuffer>& commandBuffer, UINT32 syncMask = 0xFFFFFFFF) override;
 
 		/** @copydoc RenderAPI::convertProjectionMatrix */

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

@@ -66,7 +66,7 @@ namespace bs { namespace ct
 
 		/** Binds parameter buffers and prepares any internal buffers. Must be called before execute(). */
 		void setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams, 
-					   SPtr<GpuBuffer>& linkedListHeads, SPtr<GpuBuffer>& linkedList);
+					   const SPtr<GpuBuffer>& linkedListHeads, const SPtr<GpuBuffer>& linkedList);
 
 		/** Binds the material for renderingand executes it. */
 		void execute(const RendererCamera& view);

+ 14 - 3
Source/RenderBeast/Include/BsRendererCamera.h

@@ -26,6 +26,7 @@ namespace bs { namespace ct
 		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatInvViewProj)
 		BS_PARAM_BLOCK_ENTRY(Matrix4, gMatScreenToWorld)
 		BS_PARAM_BLOCK_ENTRY(Vector2, gDeviceZToWorldZ)
+		BS_PARAM_BLOCK_ENTRY(Vector2, gNDCZToWorldZ)
 		BS_PARAM_BLOCK_ENTRY(Vector2, gNearFar)
 		BS_PARAM_BLOCK_ENTRY(Vector4I, gViewportRectangle)
 		BS_PARAM_BLOCK_ENTRY(Vector4, gClipToUVScaleOffset)
@@ -242,15 +243,25 @@ namespace bs { namespace ct
 
 	private:
 		/**
-		 * Extracts the necessary values from the projection matrix that allow you to transform device Z value into
-		 * world Z value.
+		 * Extracts the necessary values from the projection matrix that allow you to transform device Z value (range [0, 1]
+		 * into view Z value.
 		 * 
 		 * @param[in]	projMatrix	Projection matrix that was used to create the device Z value to transform.
-		 * @return					Returns two values that can be used to transform device z to world z using this formula:
+		 * @return					Returns two values that can be used to transform device z to view z using this formula:
 		 * 							z = (deviceZ + y) * x.
 		 */
 		Vector2 getDeviceZTransform(const Matrix4& projMatrix) const;
 
+		/**
+		 * Extracts the necessary values from the projection matrix that allow you to transform NDC Z value (range depending
+		 * on render API) into view Z value.
+		 * 
+		 * @param[in]	projMatrix	Projection matrix that was used to create the NDC Z value to transform.
+		 * @return					Returns two values that can be used to transform NDC z to view z using this formula:
+		 * 							z = (NDCZ + y) * x.
+		 */
+		Vector2 getNDCZTransform(const Matrix4& projMatrix) const;
+
 		RENDERER_VIEW_DESC mViewDesc;
 
 		SPtr<RenderQueue> mOpaqueQueue;

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

@@ -89,9 +89,6 @@ namespace bs { namespace ct
 	{
 		mParamsSet->setParamBlockBuffer("PerCamera", view.getPerViewBuffer(), true);
 
-		UINT32 width = view.getRenderTargets()->getWidth();
-		UINT32 height = view.getRenderTargets()->getHeight();
-
 		UINT32 numGroupsX = (mGridSize[0] + THREADGROUP_SIZE - 1) / THREADGROUP_SIZE;
 		UINT32 numGroupsY = (mGridSize[1] + THREADGROUP_SIZE - 1) / THREADGROUP_SIZE;
 		UINT32 numGroupsZ = (mGridSize[2] + THREADGROUP_SIZE - 1) / THREADGROUP_SIZE;
@@ -137,7 +134,7 @@ namespace bs { namespace ct
 	}
 
 	void LightGridLLReductionMat::setParams(const Vector3I& gridSize, const SPtr<GpuParamBlockBuffer>& gridParams,
-											SPtr<GpuBuffer>& linkedListHeads, SPtr<GpuBuffer>& linkedList)
+											const SPtr<GpuBuffer>& linkedListHeads, const SPtr<GpuBuffer>& linkedList)
 	{
 		mGridSize = gridSize;
 		UINT32 numCells = gridSize[0] * gridSize[1] * gridSize[2];

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

@@ -208,8 +208,8 @@ namespace bs { namespace ct
 
 	Vector2 RendererCamera::getDeviceZTransform(const Matrix4& projMatrix) const
 	{
-		// Returns a set of values that will transform depth buffer values (e.g. [0, 1] in DX, [-1, 1] in GL) to a distance
-		// in world space. This involes applying the inverse projection transform to the depth value. When you multiply
+		// Returns a set of values that will transform depth buffer values (in range [0, 1]) to a distance
+		// in view space. This involes applying the inverse projection transform to the depth value. When you multiply
 		// a vector with the projection matrix you get [clipX, clipY, Az + B, C * z], where we don't care about clipX/clipY.
 		// A is [2, 2], B is [2, 3] and C is [3, 2] elements of the projection matrix (only ones that matter for our depth 
 		// value). The hardware will also automatically divide the z value with w to get the depth, therefore the final 
@@ -244,6 +244,36 @@ namespace bs { namespace ct
 		return output;
 	}
 
+	Vector2 RendererCamera::getNDCZTransform(const Matrix4& projMatrix) const
+	{
+		// Returns a set of values that will transform depth buffer values (e.g. [0, 1] in DX, [-1, 1] in GL) to a distance
+		// in view space. This involes applying the inverse projection transform to the depth value. When you multiply
+		// a vector with the projection matrix you get [clipX, clipY, Az + B, C * z], where we don't care about clipX/clipY.
+		// A is [2, 2], B is [2, 3] and C is [3, 2] elements of the projection matrix (only ones that matter for our depth 
+		// value). The hardware will also automatically divide the z value with w to get the depth, therefore the final 
+		// formula is:
+		// depth = (Az + B) / (C * z)
+
+		// To get the z coordinate back we simply do the opposite: 
+		// z = B / (depth * C - A)
+
+		// Are we reorganize it because it needs to fit the "(1.0f / (depth + y)) * x" format used in the shader:
+		// z = 1.0f / (depth - A/C) * B/C
+
+		RenderAPI& rapi = RenderAPI::instance();
+		const RenderAPIInfo& rapiInfo = rapi.getAPIInfo();
+
+		float a = projMatrix[2][2];
+		float b = projMatrix[2][3];
+		float c = projMatrix[3][2];
+
+		Vector2 output;
+		output.x = b / c;
+		output.y = - a / c;
+
+		return output;
+	}
+
 	void RendererCamera::updatePerViewBuffer()
 	{
 		Matrix4 viewProj = mViewDesc.projTransform * mViewDesc.viewTransform;
@@ -270,6 +300,7 @@ namespace bs { namespace ct
 		gPerCameraParamDef.gViewDir.set(mParamBuffer, mViewDesc.viewDirection);
 		gPerCameraParamDef.gViewOrigin.set(mParamBuffer, mViewDesc.viewOrigin);
 		gPerCameraParamDef.gDeviceZToWorldZ.set(mParamBuffer, getDeviceZTransform(mViewDesc.projTransform));
+		gPerCameraParamDef.gNDCZToWorldZ.set(mParamBuffer, getNDCZTransform(mViewDesc.projTransform));
 
 		Vector2 nearFar(mViewDesc.nearPlane, mViewDesc.farPlane);
 		gPerCameraParamDef.gNearFar.set(mParamBuffer, nearFar);