Browse Source

Mesh normals and tangents now use 8-bit unorm data format instead of the 32-bit floating point format, in order to reduce GPU bandwidth

BearishSun 9 years ago
parent
commit
a9d20707e7

BIN
Data/Engine/GUISkin.asset


BIN
Data/Engine/Includes/NormalVertexInput.bslinc.asset


BIN
Data/Engine/Includes/SkinnedVertexInput.bslinc.asset


BIN
Data/Engine/ResourceManifest.asset


BIN
Data/Engine/Shaders/Default.bsl.asset


BIN
Data/Engine/Shaders/Diffuse.bsl.asset


BIN
Data/Engine/Timestamp.asset


BIN
Data/Engine/arial.ttf.asset


+ 6 - 3
Data/Raw/Engine/Includes/NormalVertexInput.bslinc

@@ -36,8 +36,8 @@ Technique : base("NormalVertexInput") =
 			
 			
 			float3x3 getTangentToLocal(VertexInput input, out float tangentSign)
 			float3x3 getTangentToLocal(VertexInput input, out float tangentSign)
 			{
 			{
-				float3 normal = input.normal;
-				float4 tangent = input.tangent;
+				float3 normal = input.normal * 2.0f - 1.0f;
+				float4 tangent = input.tangent * 2.0f - 1.0f;
 				float3 bitangent = cross(normal, tangent.xyz) * tangent.w;
 				float3 bitangent = cross(normal, tangent.xyz) * tangent.w;
 				tangentSign = tangent.w * gWorldDeterminantSign;
 				tangentSign = tangent.w * gWorldDeterminantSign;
 				
 				
@@ -121,9 +121,12 @@ Technique : base("NormalVertexInput") =
 
 
 			void getVertexWorldPosition(VertexIntermediate intermediate, out vec4 result)
 			void getVertexWorldPosition(VertexIntermediate intermediate, out vec4 result)
 			{
 			{
+				vec3 normal = bs_normal * 2.0f - 1.0f;
+				vec4 tangent = bs_tangent * 2.0f - 1.0f;
+			
 				float tangentSign;
 				float tangentSign;
 				mat3 tangentToLocal;
 				mat3 tangentToLocal;
-				getTangentToLocal(bs_normal, bs_tangent, tangentSign, tangentToLocal);
+				getTangentToLocal(normal, tangent, tangentSign, tangentToLocal);
 				
 				
 				mat3 tangentToWorld = mat3(gMatWorldNoScale) * tangentToLocal;
 				mat3 tangentToWorld = mat3(gMatWorldNoScale) * tangentToLocal;
 				result.worldNormal = tangentToWorld[2]; // Normal basis vector
 				result.worldNormal = tangentToWorld[2]; // Normal basis vector

+ 6 - 6
Data/Raw/Engine/Includes/SkinnedVertexInput.bslinc

@@ -69,10 +69,10 @@ Technique : base("SkinnedVertexInput") =
 			
 			
 			float3x3 getSkinnedTangentToLocal(VertexInput input, float3x4 blendMatrix, out float tangentSign)
 			float3x3 getSkinnedTangentToLocal(VertexInput input, float3x4 blendMatrix, out float tangentSign)
 			{
 			{
-				tangentSign = input.tangent.w;
+				tangentSign = input.tangent.w * 2.0f - 1.0f;
 			
 			
-				float3 normal = input.normal;
-				float3 tangent = input.tangent.xyz;
+				float3 normal = input.normal * 2.0f - 1.0f;
+				float3 tangent = input.tangent.xyz * 2.0f - 1.0f;
 				
 				
 				#if USE_BLEND_SHAPES
 				#if USE_BLEND_SHAPES
 					normal = normalize(normal + input.deltaNormal * input.deltaNormal.w);
 					normal = normalize(normal + input.deltaNormal * input.deltaNormal.w);
@@ -203,10 +203,10 @@ Technique : base("SkinnedVertexInput") =
 			
 			
 			void getSkinnedTangentToLocal(mat4x3 blendMatrix, out float tangentSign, out mat3x3 tangentToLocal)
 			void getSkinnedTangentToLocal(mat4x3 blendMatrix, out float tangentSign, out mat3x3 tangentToLocal)
 			{
 			{
-				tangentSign = bs_tangent.w;
+				tangentSign = bs_tangent.w * 2.0f - 1.0f;
 			
 			
-				vec3 normal = bs_normal;
-				vec3 tangent = bs_tangent.xyz;
+				vec3 normal = bs_normal * 2.0f - 1.0f;
+				vec3 tangent = bs_tangent.xyz * 2.0f - 1.0f;
 				
 				
 				#if USE_BLEND_SHAPES
 				#if USE_BLEND_SHAPES
 					normal = normalize(normal + bs_normal1 * bs_normal1.w);
 					normal = normalize(normal + bs_normal1 * bs_normal1.w);

+ 40 - 0
Source/BansheeCore/Include/BsRendererMeshData.h

@@ -224,6 +224,46 @@ namespace BansheeEngine
 		RendererMeshData(UINT32 numVertices, UINT32 numIndices, VertexLayout layout, IndexType indexType = IT_32BIT);
 		RendererMeshData(UINT32 numVertices, UINT32 numIndices, VertexLayout layout, IndexType indexType = IT_32BIT);
 		RendererMeshData(const SPtr<MeshData>& meshData);
 		RendererMeshData(const SPtr<MeshData>& meshData);
 
 
+		/** 
+		 * Encodes normals from 32-bit float format into 4D 8-bit packed format. 
+		 *
+		 * @param[in]	source			Buffer containing data to encode. Must have @p count entries.
+		 * @param[out]	destination		Buffer to output the data to. Must have @p count entries, each 32-bits.
+		 * @param[in]	count			Number of entries in the @p source and @p destination arrays.
+		 * @param[in]	stride			Distance between two entries in the @p destination buffer, in bytes.
+		 */
+		void packNormals(Vector3* source, UINT8* destination, UINT32 count, UINT32 stride);
+
+		/** 
+		 * Encodes normals from 32-bit float format into 4D 8-bit packed format. 
+		 *
+		 * @param[in]	source			Buffer containing data to encode. Must have @p count entries.
+		 * @param[out]	destination		Buffer to output the data to. Must have @p count entries, each 32-bits.
+		 * @param[in]	count			Number of entries in the @p source and @p destination arrays.
+		 * @param[in]	stride			Distance between two entries in the @p destination buffer, in bytes.
+		 */
+		void packNormals(Vector4* source, UINT8* destination, UINT32 count, UINT32 stride);
+
+		/** 
+		 * Decodes normals from 4D 8-bit packed format into a 32-bit float format. 
+		 *
+		 * @param[in]	source			Buffer containing data to encode. Must have @p count entries, each 32-bits.
+		 * @param[out]	destination		Buffer to output the data to. Must have @p count entries.
+		 * @param[in]	count			Number of entries in the @p source and @p destination arrays.
+		 * @param[in]	stride			Distance between two entries in the @p source buffer, in bytes.
+		 */
+		void unpackNormals(UINT8* source, Vector3* destination, UINT32 count, UINT32 stride);
+
+		/** 
+		 * Decodes normals from 4D 8-bit packed format into a 32-bit float format. 
+		 *
+		 * @param[in]	source			Buffer containing data to encode. Must have @p count entries, each 32-bits.
+		 * @param[out]	destination		Buffer to output the data to. Must have @p count entries.
+		 * @param[in]	count			Number of entries in the @p source and @p destination arrays.
+		 * @param[in]	stride			Distance between two entries in the @p source buffer, in bytes.
+		 */
+		void unpackNormals(UINT8* source, Vector4* destination, UINT32 count, UINT32 stride);
+
 		SPtr<MeshData> mMeshData;
 		SPtr<MeshData> mMeshData;
 	};
 	};
 
 

+ 1 - 0
Source/BansheeCore/Include/BsVertexDeclaration.h

@@ -52,6 +52,7 @@ namespace BansheeEngine
 		VET_UINT1 = 21,  /**< 1D 32-bit signed integer value */
 		VET_UINT1 = 21,  /**< 1D 32-bit signed integer value */
 		VET_UINT2 = 22,  /**< 2D 32-bit signed integer value */
 		VET_UINT2 = 22,  /**< 2D 32-bit signed integer value */
 		VET_UINT3 = 23,  /**< 3D 32-bit signed integer value */
 		VET_UINT3 = 23,  /**< 3D 32-bit signed integer value */
+		VET_UBYTE4_NORM = 24, /**< 4D 8-bit unsigned integer interpreted as a normalized value in [0, 1] range. */
     };
     };
 
 
 	/**	Describes a single vertex element in a vertex declaration. */
 	/**	Describes a single vertex element in a vertex declaration. */

+ 92 - 6
Source/BansheeCore/Source/BsRendererMeshData.cpp

@@ -55,7 +55,10 @@ namespace BansheeEngine
 		UINT32 numElements = mMeshData->getNumVertices();
 		UINT32 numElements = mMeshData->getNumVertices();
 		assert(numElements * sizeof(Vector3) == size);
 		assert(numElements * sizeof(Vector3) == size);
 
 
-		mMeshData->getVertexData(VES_NORMAL, (UINT8*)buffer, size);
+		UINT8* normalSrc = mMeshData->getElementData(VES_NORMAL);
+		UINT32 stride = mMeshData->getVertexDesc()->getVertexStride(0);
+
+		unpackNormals(normalSrc, buffer, numElements, stride);
 	}
 	}
 
 
 	void RendererMeshData::setNormals(Vector3* buffer, UINT32 size)
 	void RendererMeshData::setNormals(Vector3* buffer, UINT32 size)
@@ -66,7 +69,10 @@ namespace BansheeEngine
 		UINT32 numElements = mMeshData->getNumVertices();
 		UINT32 numElements = mMeshData->getNumVertices();
 		assert(numElements * sizeof(Vector3) == size);
 		assert(numElements * sizeof(Vector3) == size);
 
 
-		mMeshData->setVertexData(VES_NORMAL, (UINT8*)buffer, size);
+		UINT8* normalDst = mMeshData->getElementData(VES_NORMAL);
+		UINT32 stride = mMeshData->getVertexDesc()->getVertexStride(0);
+
+		packNormals(buffer, normalDst, numElements, stride);
 	}
 	}
 
 
 	void RendererMeshData::getTangents(Vector4* buffer, UINT32 size)
 	void RendererMeshData::getTangents(Vector4* buffer, UINT32 size)
@@ -77,7 +83,10 @@ namespace BansheeEngine
 		UINT32 numElements = mMeshData->getNumVertices();
 		UINT32 numElements = mMeshData->getNumVertices();
 		assert(numElements * sizeof(Vector4) == size);
 		assert(numElements * sizeof(Vector4) == size);
 
 
-		mMeshData->getVertexData(VES_TANGENT, (UINT8*)buffer, size);
+		UINT8* tangentSrc = mMeshData->getElementData(VES_TANGENT);
+		UINT32 stride = mMeshData->getVertexDesc()->getVertexStride(0);
+
+		unpackNormals(tangentSrc, buffer, numElements, stride);
 	}
 	}
 
 
 	void RendererMeshData::setTangents(Vector4* buffer, UINT32 size)
 	void RendererMeshData::setTangents(Vector4* buffer, UINT32 size)
@@ -88,7 +97,10 @@ namespace BansheeEngine
 		UINT32 numElements = mMeshData->getNumVertices();
 		UINT32 numElements = mMeshData->getNumVertices();
 		assert(numElements * sizeof(Vector4) == size);
 		assert(numElements * sizeof(Vector4) == size);
 
 
-		mMeshData->setVertexData(VES_TANGENT, (UINT8*)buffer, size);
+		UINT8* tangentDst = mMeshData->getElementData(VES_TANGENT);
+		UINT32 stride = mMeshData->getVertexDesc()->getVertexStride(0);
+
+		packNormals(buffer, tangentDst, numElements, stride);
 	}
 	}
 
 
 	void RendererMeshData::getColors(Color* buffer, UINT32 size)
 	void RendererMeshData::getColors(Color* buffer, UINT32 size)
@@ -340,10 +352,10 @@ namespace BansheeEngine
 			vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
 			vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
 
 
 		if ((intType & (INT32)VertexLayout::Normal) != 0)
 		if ((intType & (INT32)VertexLayout::Normal) != 0)
-			vertexDesc->addVertElem(VET_FLOAT3, VES_NORMAL);
+			vertexDesc->addVertElem(VET_UBYTE4_NORM, VES_NORMAL);
 
 
 		if ((intType & (INT32)VertexLayout::Tangent) != 0)
 		if ((intType & (INT32)VertexLayout::Tangent) != 0)
-			vertexDesc->addVertElem(VET_FLOAT4, VES_TANGENT);
+			vertexDesc->addVertElem(VET_UBYTE4_NORM, VES_TANGENT);
 
 
 		if ((intType & (INT32)VertexLayout::UV0) != 0)
 		if ((intType & (INT32)VertexLayout::UV0) != 0)
 			vertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD, 0);
 			vertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD, 0);
@@ -362,4 +374,78 @@ namespace BansheeEngine
 
 
 		return vertexDesc;
 		return vertexDesc;
 	}
 	}
+
+	union PackedNormal
+	{
+		struct
+		{
+			UINT8 x;
+			UINT8 y;
+			UINT8 z;
+			UINT8 w;
+		};
+
+		UINT32 packed;
+	};
+
+	void RendererMeshData::packNormals(Vector3* source, UINT8* destination, UINT32 count, UINT32 stride)
+	{
+		UINT8* ptr = destination;
+		for(UINT32 i = 0; i < count; i++)
+		{
+			PackedNormal& packed = *(PackedNormal*)ptr;
+			packed.x = Math::clamp((int)(source[i].x * 127.5f + 127.5f), 0, 255);
+			packed.y = Math::clamp((int)(source[i].y * 127.5f + 127.5f), 0, 255);
+			packed.z = Math::clamp((int)(source[i].z * 127.5f + 127.5f), 0, 255);
+			packed.w = 128;
+
+			ptr += stride;
+		}
+	}
+
+	void RendererMeshData::packNormals(Vector4* source, UINT8* destination, UINT32 count, UINT32 stride)
+	{
+		UINT8* ptr = destination;
+		for (UINT32 i = 0; i < count; i++)
+		{
+			PackedNormal& packed = *(PackedNormal*)ptr;
+			packed.x = Math::clamp((int)(source[i].x * 127.5f + 127.5f), 0, 255);
+			packed.y = Math::clamp((int)(source[i].y * 127.5f + 127.5f), 0, 255);
+			packed.z = Math::clamp((int)(source[i].z * 127.5f + 127.5f), 0, 255);
+			packed.w = Math::clamp((int)(source[i].w * 127.5f + 127.5f), 0, 255);
+
+			ptr += stride;
+		}
+	}
+
+	void RendererMeshData::unpackNormals(UINT8* source, Vector3* destination, UINT32 count, UINT32 stride)
+	{
+		UINT8* ptr = source;
+		for (UINT32 i = 0; i < count; i++)
+		{
+			PackedNormal& packed = *(PackedNormal*)ptr;
+
+			destination[i].x = (packed.x * 2.0f - 1.0f);
+			destination[i].y = (packed.y * 2.0f - 1.0f);
+			destination[i].z = (packed.z * 2.0f - 1.0f);
+
+			ptr += stride;
+		}
+	}
+
+	void RendererMeshData::unpackNormals(UINT8* source, Vector4* destination, UINT32 count, UINT32 stride)
+	{
+		UINT8* ptr = source;
+		for (UINT32 i = 0; i < count; i++)
+		{
+			PackedNormal& packed = *(PackedNormal*)ptr;
+
+			destination[i].x = (packed.x * 2.0f - 1.0f);
+			destination[i].y = (packed.y * 2.0f - 1.0f);
+			destination[i].z = (packed.z * 2.0f - 1.0f);
+			destination[i].w = (packed.w * 2.0f - 1.0f);
+
+			ptr += stride;
+		}
+	}
 }
 }

+ 3 - 0
Source/BansheeCore/Source/BsVertexDeclaration.cpp

@@ -27,6 +27,8 @@ namespace BansheeEngine
 		case VET_COLOR_ABGR:
 		case VET_COLOR_ABGR:
 		case VET_COLOR_ARGB:
 		case VET_COLOR_ARGB:
 			return sizeof(RGBA);
 			return sizeof(RGBA);
+		case VET_UBYTE4_NORM:
+			return sizeof(UINT32);
 		case VET_FLOAT1:
 		case VET_FLOAT1:
 			return sizeof(float);
 			return sizeof(float);
 		case VET_FLOAT2:
 		case VET_FLOAT2:
@@ -100,6 +102,7 @@ namespace BansheeEngine
 		case VET_INT4:
 		case VET_INT4:
 		case VET_UINT4:
 		case VET_UINT4:
 		case VET_UBYTE4:
 		case VET_UBYTE4:
+		case VET_UBYTE4_NORM:
 			return 4;
 			return 4;
 		}
 		}
 
 

+ 1 - 0
Source/BansheeD3D11RenderAPI/Source/BsD3D11Mappings.cpp

@@ -278,6 +278,7 @@ namespace BansheeEngine
 		case VET_COLOR:
 		case VET_COLOR:
 		case VET_COLOR_ABGR:
 		case VET_COLOR_ABGR:
 		case VET_COLOR_ARGB:
 		case VET_COLOR_ARGB:
+		case VET_UBYTE4_NORM:
 			return DXGI_FORMAT_R8G8B8A8_UNORM;
 			return DXGI_FORMAT_R8G8B8A8_UNORM;
 		case VET_FLOAT1:
 		case VET_FLOAT1:
 			return DXGI_FORMAT_R32_FLOAT;
 			return DXGI_FORMAT_R32_FLOAT;

+ 1 - 0
Source/BansheeD3D9RenderAPI/Source/BsD3D9Mappings.cpp

@@ -336,6 +336,7 @@ namespace BansheeEngine
 		case VET_COLOR:
 		case VET_COLOR:
 		case VET_COLOR_ABGR:
 		case VET_COLOR_ABGR:
 		case VET_COLOR_ARGB:
 		case VET_COLOR_ARGB:
+		case VET_UBYTE4_NORM:
 			return D3DDECLTYPE_D3DCOLOR;
 			return D3DDECLTYPE_D3DCOLOR;
 		case VET_FLOAT1:
 		case VET_FLOAT1:
 			return D3DDECLTYPE_FLOAT1;
 			return D3DDECLTYPE_FLOAT1;

+ 1 - 0
Source/BansheeGLRenderAPI/Source/BsGLHardwareBufferManager.cpp

@@ -93,6 +93,7 @@ namespace BansheeEngine
 			case VET_COLOR_ABGR:
 			case VET_COLOR_ABGR:
 			case VET_COLOR_ARGB:
 			case VET_COLOR_ARGB:
             case VET_UBYTE4:
             case VET_UBYTE4:
+			case VET_UBYTE4_NORM:
                 return GL_UNSIGNED_BYTE;
                 return GL_UNSIGNED_BYTE;
             default:
             default:
                 return 0;
                 return 0;

+ 1 - 0
Source/BansheeGLRenderAPI/Source/BsGLVertexArrayObjectManager.cpp

@@ -167,6 +167,7 @@ namespace BansheeEngine
 			case VET_COLOR:
 			case VET_COLOR:
 			case VET_COLOR_ABGR:
 			case VET_COLOR_ABGR:
 			case VET_COLOR_ARGB:
 			case VET_COLOR_ARGB:
+			case VET_UBYTE4_NORM:
 				normalized = GL_TRUE;
 				normalized = GL_TRUE;
 				break;
 				break;
 			default:
 			default:

+ 8 - 0
Source/MBansheeEngine/Animation/Animation.cs

@@ -1076,6 +1076,14 @@ namespace BansheeEngine
     /// </summary>
     /// </summary>
     public class Blend1DInfo
     public class Blend1DInfo
     {
     {
+        public Blend1DInfo()
+        { }
+
+        public Blend1DInfo(int numClips)
+        {
+            clips = new BlendClipInfo[numClips];
+        }
+
         public BlendClipInfo[] clips;
         public BlendClipInfo[] clips;
     }
     }