From 15740faf9fe9fe4be08965098bbf2947e096aeeb Mon Sep 17 00:00:00 2001 From: chai Date: Wed, 14 Aug 2019 22:50:43 +0800 Subject: +Unity Runtime code --- Runtime/Filters/Mesh/CompressedMesh.cpp | 755 ++++++++++++++++++++++++++++++++ 1 file changed, 755 insertions(+) create mode 100644 Runtime/Filters/Mesh/CompressedMesh.cpp (limited to 'Runtime/Filters/Mesh/CompressedMesh.cpp') diff --git a/Runtime/Filters/Mesh/CompressedMesh.cpp b/Runtime/Filters/Mesh/CompressedMesh.cpp new file mode 100644 index 0000000..02cc74c --- /dev/null +++ b/Runtime/Filters/Mesh/CompressedMesh.cpp @@ -0,0 +1,755 @@ +#include "UnityPrefix.h" +#include "CompressedMesh.h" +#include "LodMesh.h" +#include "Runtime/Animation/AnimationCurveUtility.h" + + +#define sqr(x) ((x)*(x)) + +void PackedFloatVector::PackFloats(float *data, int itemCountInChunk, int chunkStride, int numChunks, int bitSize, bool adjustBitSize) +{ + float maxf = -std::numeric_limits::infinity(); + float minf = std::numeric_limits::infinity(); + float* end = Stride (data, numChunks * chunkStride); + for(float* it = data; it != end; it = Stride (it, chunkStride)) + { + for (int i=0; i it[i]) + minf = it[i]; + } + } + + m_Range = maxf-minf; + + if(adjustBitSize) + bitSize += int(ceilf(Log2(m_Range))); + if(bitSize > 32) + bitSize = 32; + + m_Start = minf; + m_NumItems = numChunks * itemCountInChunk; + m_BitSize = bitSize; + m_Data.resize((m_NumItems * bitSize + 7)/8, 0); + + + float scale = 1.0/m_Range; + + int indexPos = 0; + int bitPos = 0; + + for(float* it = data; it != end; it = Stride (it, chunkStride)) + { + for(int i=0; i 1) scaled = 1; + + UInt32 x = UInt32(scaled * ((1 << (m_BitSize)) - 1)); + + int bits = 0; + while(bits < m_BitSize) + { + m_Data[indexPos] |= (x >> bits) << bitPos; + int num = std::min( m_BitSize-bits, 8-bitPos); + bitPos += num; + bits += num; + if(bitPos == 8) + { + indexPos++; + bitPos = 0; + } + } + } + } +} + +void PackedFloatVector::UnpackFloats(float *data, int itemCountInChunk, int chunkStride, int start, int numChunks) +{ + int bitPos = m_BitSize*start; + int indexPos = bitPos/8; + bitPos %= 8; + + float scale = 1.0/m_Range; + if (numChunks == -1) + numChunks = m_NumItems / itemCountInChunk; + + for(float* end = Stride (data, chunkStride * numChunks); data != end; data = Stride (data, chunkStride)) + { + for (int i=0; i> bitPos) << bits; + int num = std::min( m_BitSize-bits, 8-bitPos); + bitPos += num; + bits += num; + if(bitPos == 8) + { + indexPos++; + bitPos = 0; + } + } + x &= (1 << m_BitSize) - 1; + data[i] = (x / (scale * ((1 << (m_BitSize)) - 1))) + m_Start; + } + } +} + +template void PackedIntVector::PackInts(IntSize *data, int numItems) +{ + // make sure that the intsize is an unsigned type + Assert( (IntSize)0 < (IntSize)-1 ); + + UInt32 maxi = 0; + for(int i=0; i> bits) << bitPos; + int num = std::min( m_BitSize-bits, 8-bitPos); + bitPos += num; + bits += num; + if(bitPos == 8) + { + indexPos++; + bitPos = 0; + } + } + } +} + +template void PackedIntVector::UnpackInts(IntSize *data) +{ + int indexPos = 0; + int bitPos = 0; + for(int i=0; i> bitPos) << bits; + int num = std::min( m_BitSize-bits, 8-bitPos); + bitPos += num; + bits += num; + if(bitPos == 8) + { + indexPos++; + bitPos = 0; + } + } + data[i] &= (1ULL << m_BitSize) - 1; + } +} + + +void PackedQuatVector::PackQuats(Quaternionf *data, int numItems) +{ + m_NumItems = numItems; + m_Data.resize(numItems * (32/8), 0); + + int indexPos = 0; + int bitPos = 0; + + for(int i=0; i max) + { + max = fabs(q.y); + flags = 1; + if(q.y<0) + flags |= 4; + } + if(fabs(q.z) > max) + { + max = fabs(q.z); + flags = 2; + if(q.z<0) + flags |= 4; + } + if(fabs(q.w) > max) + { + max = fabs(q.w); + flags = 3; + if(q.w<0) + flags |= 4; + } + int bits = 0; + while(bits < 3) + { + m_Data[indexPos] |= (flags >> bits) << bitPos; + int num = std::min( 3-bits, 8-bitPos); + bitPos += num; + bits += num; + if(bitPos == 8) + { + indexPos++; + bitPos = 0; + } + } + for(int j=0;j<4;j++) + { + if((flags&3) != j) + { + int bitSize = (((flags&3)+1)%4 == j)?9:10; + float scaled = (q[j] + 1) * 0.5; + if(scaled < 0) scaled = 0; + if(scaled > 1) scaled = 1; + + UInt32 x = UInt32(scaled * ((1 << bitSize) - 1)); + + bits = 0; + while(bits < bitSize) + { + m_Data[indexPos] |= (x >> bits) << bitPos; + int num = std::min( bitSize-bits, 8-bitPos); + bitPos += num; + bits += num; + if(bitPos == 8) + { + indexPos++; + bitPos = 0; + } + } + } + } + } +} + +void PackedQuatVector::UnpackQuats(Quaternionf *data) +{ + int indexPos = 0; + int bitPos = 0; + + for(int i=0; i> bitPos) << bits; + int num = std::min( 3-bits, 8-bitPos); + bitPos += num; + bits += num; + if(bitPos == 8) + { + indexPos++; + bitPos = 0; + } + } + flags &= 7; + + + Quaternionf &q = data[i]; + float sum = 0; + for(int j=0;j<4;j++) + { + if((flags&3) != j) + { + int bitSize = (((flags&3)+1)%4 == j)?9:10; + UInt32 x = 0; + + bits = 0; + while(bits < bitSize) + { + x |= (m_Data[indexPos] >> bitPos) << bits; + int num = std::min( bitSize-bits, 8-bitPos); + bitPos += num; + bits += num; + if(bitPos == 8) + { + indexPos++; + bitPos = 0; + } + } + x &= (1 << bitSize) - 1; + q[j] = (x / (0.5 * ((1 << (bitSize)) - 1))) - 1; + sum += sqr(q[j]); + } + } + + int lastComponent = flags&3; + q[lastComponent] = FastSqrt(1 - sum); + if(flags & 4) + q[lastComponent] = -q[lastComponent]; + } +} + +void CompressedMesh::Compress(Mesh &src, int compression) +{ + int numVertices = src.GetVertexCount(); + + int vertexBits = 0; + switch(compression) + { + case kMeshCompressionHigh: vertexBits = 10; break; + case kMeshCompressionMed: vertexBits = 16; break; + case kMeshCompressionLow: vertexBits = 20; break; + } + m_Vertices.PackFloats((float*)src.GetChannelPointer(kShaderChannelVertex), 3, src.GetStride (kShaderChannelVertex), numVertices, vertexBits, false); + + //Possible optimization: use Edgebreaker algorithm + //for 1.8 bits per triangle connectivity information + //http://www.gvu.gatech.edu/~jarek/edgebreaker/eb/ + + int numIndices = src.m_IndexBuffer.size(); + numIndices/=2; + + m_Triangles.PackInts((UInt16*)&src.m_IndexBuffer[0],numIndices); + + if(src.IsAvailable(kShaderChannelTexCoord0)) + { + int uvBits = 0; + switch(compression) + { + case kMeshCompressionHigh: uvBits = 8; break; + case kMeshCompressionMed: uvBits = 10; break; + case kMeshCompressionLow: uvBits = 16; break; + } + if(src.IsAvailable(kShaderChannelTexCoord1)) + { + Vector2f *uv12 = new Vector2f[numVertices*2]; + src.ExtractUvArray(0, uv12); + src.ExtractUvArray(1, uv12 + numVertices); + m_UV.PackFloats(&uv12->x, 2, sizeof(Vector2f), numVertices*2, uvBits, true); + delete[] uv12; + } + else + m_UV.PackFloats((float*)src.GetChannelPointer (kShaderChannelTexCoord0), 2, src.GetStride (kShaderChannelTexCoord0), numVertices, uvBits, true); + } + else if(src.IsAvailable(kShaderChannelTexCoord1)) + ErrorString( "Mesh compression doesn't work on Meshes wich only have a UV1 channel but no UV0 channel. UVs will be dropped." ); + + if(src.IsAvailable (kShaderChannelNormal)) + { + int normalBits = 0; + switch(compression) + { + case kMeshCompressionHigh: normalBits = 6; break; + case kMeshCompressionMed: normalBits = 8; break; + case kMeshCompressionLow: normalBits = 8; break; + } + + float *normals = new float[numVertices*2]; + UInt32 *signs = new UInt32[numVertices]; + StrideIterator n = src.GetNormalBegin (); + for(int i=0;ix; + normals[i*2+1] = n->y; + signs[i] = n->z>0?1:0; + } + m_Normals.PackFloats(normals, 2, sizeof (float) * 2, numVertices, normalBits, false); + m_NormalSigns.PackInts(signs, numVertices); + delete[] normals; + delete[] signs; + } + + if(src.IsAvailable (kShaderChannelTangent)) + { + int normalBits = 0; + switch(compression) + { + case kMeshCompressionHigh: normalBits = 6; break; + case kMeshCompressionMed: normalBits = 8; break; + case kMeshCompressionLow: normalBits = 8; break; + } + + float *tangents = new float[numVertices*2]; + UInt32 *signs = new UInt32[numVertices*2]; + StrideIterator t = src.GetTangentBegin (); + for(int i=0;ix; + tangents[i*2+1] = t->y; + signs[i*2+0] = t->z>0?1:0; + signs[i*2+1] = t->w>0?1:0; + } + m_Tangents.PackFloats(tangents, 2, sizeof (float) * 2, numVertices, normalBits, false); + m_TangentSigns.PackInts(signs, numVertices*2); + delete[] tangents; + delete[] signs; + } + + // TODO: do an actual compression + if(src.IsAvailable (kShaderChannelColor)) + { + dynamic_array tempColors (numVertices, kMemTempAlloc); + std::transform (src.GetColorBegin (), src.GetColorEnd (), tempColors.begin (), OpColorRGBA32ToUInt32()); + m_Colors.PackInts (tempColors.data (), tempColors.size ()); + } + + BoneInfluence* influence = src.GetBoneWeights(); + if(influence) + { + UInt32 *weights = new UInt32[numVertices*3]; + UInt32 *indices = new UInt32[numVertices*4]; + int weightPos = 0; + int boneIndexPos = 0; + for(int i=0;i0&&influence[i].weight[lastNonZero]==0;lastNonZero--) + {} + + + for(j=0;j<3 && j<=lastNonZero && sum<31;j++) + { + weights[weightPos] = UInt32(influence[i].weight[j] * 31); + indices[boneIndexPos++] = influence[i].boneIndex[j]; + sum += weights[weightPos++]; + } + if(lastNonZero<3) + { + //we stored less then 3 weights, but they don't add up to one, due to quantization + //inprecision. + //Add the difference, so the math works out on decompression. + if(sum<31) + weights[weightPos-1] += 31-sum; + } + + //we stored three weights, but they don't add up to one. we don't need to store the fourth weight + //(as it can be calculated from the other three), but we need the bone index. + else if(sum<31) + indices[boneIndexPos++] = influence[i].boneIndex[j]; + } + + m_Weights.PackInts(weights, weightPos); + m_BoneIndices.PackInts(indices, boneIndexPos); + + delete[] weights; + delete[] indices; + } +} + +void CompressedMesh::Decompress(Mesh &src) +{ + int numIndices = m_Triangles.Count(); + src.m_IndexBuffer.resize(numIndices * 2); + m_Triangles.UnpackInts((UInt16*)&src.m_IndexBuffer[0]); + + int numVertices = m_Vertices.Count()/3; + unsigned decompressedFormat = 0; + if (m_Vertices.Count ()) decompressedFormat |= VERTEX_FORMAT1(Vertex); + if (m_Normals.Count()) decompressedFormat |= VERTEX_FORMAT1(Normal); + if (m_UV.Count()) decompressedFormat |= VERTEX_FORMAT1(TexCoord0); + if (m_UV.Count() == numVertices * 4) decompressedFormat |= VERTEX_FORMAT1(TexCoord1); + if (m_Tangents.Count()) decompressedFormat |= VERTEX_FORMAT1(Tangent); + if (m_Colors.Count()) decompressedFormat |= VERTEX_FORMAT1(Color); + + src.ResizeVertices(numVertices, decompressedFormat); + Assert (src.GetVertexCount () == numVertices); + + m_Vertices.UnpackFloats((float*)src.GetChannelPointer (kShaderChannelVertex), 3, src.GetStride (kShaderChannelVertex)); + + if(m_UV.Count()) + { + m_UV.UnpackFloats((float*)src.GetChannelPointer (kShaderChannelTexCoord0), 2, src.GetStride (kShaderChannelTexCoord0), 0, numVertices); + + if(m_UV.Count()==numVertices * 4) + { + m_UV.UnpackFloats((float*)src.GetChannelPointer (kShaderChannelTexCoord1), 2, src.GetStride (kShaderChannelTexCoord1), numVertices*2, numVertices); + } + } + + // TODO: This never gets written. Unity 3.4 and 3.5 never wrote this data. + // Most likely no version ever did. Remove code and bindpose serialization. + if(m_BindPoses.Count()) + { + src.m_Bindpose.resize_initialized(m_BindPoses.Count()/16); + m_BindPoses.UnpackFloats(src.m_Bindpose[0].m_Data, 16, sizeof(float) * 16); + } + + if(m_Normals.Count()) + { + float *normalData = new float[m_Normals.Count()]; + UInt32 *signs = new UInt32[m_NormalSigns.Count()]; + + m_Normals.UnpackFloats(normalData, 2, sizeof(float) * 2); + m_NormalSigns.UnpackInts(signs); + + StrideIterator n = src.GetNormalBegin (); + for(int i=0;ix = normalData[i*2+0]; + n->y = normalData[i*2+1]; + float zsqr = 1 - sqr(n->x) - sqr(n->y); + if(zsqr >= 0) + n->z = FastSqrt( zsqr ); + else + { + n->z = 0; + *n = Normalize(*n); + } + if(signs[i]==0) + n->z = -n->z; + } + + delete[] normalData; + delete[] signs; + } + + if(m_Tangents.Count()) + { + float *tangentData = new float[m_Tangents.Count()]; + UInt32 *signs = new UInt32[m_TangentSigns.Count()]; + + m_Tangents.UnpackFloats(tangentData, 2, sizeof(float) * 2); + m_TangentSigns.UnpackInts(signs); + + StrideIterator t = src.GetTangentBegin (); + for(int i=0;ix = tangentData[i*2+0]; + t->y = tangentData[i*2+1]; + float zsqr = 1-sqr(tangentData[i*2+0])-sqr(tangentData[i*2+1]); + if(zsqr >= 0.0f) + t->z = FastSqrt( zsqr ); + else + { + t->z = 0; + *(Vector3f*)(&*t) = Normalize(*(Vector3f*)(&*t)); + } + if(signs[i*2+0]==0) + t->z = -t->z; + + t->w = signs[i*2+1]?1.0:-1.0; + } + + delete[] tangentData; + delete[] signs; + } + + // TODO: do an actual compression + if (m_Colors.Count()) + { + dynamic_array tempColors (m_Colors.Count (), kMemTempAlloc); + m_Colors.UnpackInts (tempColors.data ()); + Assert (tempColors.size () == src.GetVertexCount ()); + strided_copy ((ColorRGBA32*)tempColors.begin (), (ColorRGBA32*)tempColors.end (), src.GetColorBegin ()); + } + + if(m_Weights.Count()) + { + UInt32 *weights = new UInt32[m_Weights.Count()]; + m_Weights.UnpackInts(weights); + UInt32 *boneIndices = new UInt32[m_BoneIndices.Count()]; + m_BoneIndices.UnpackInts(boneIndices); + src.m_Skin.resize_uninitialized(numVertices); + int bonePos = 0; + int boneIndexPos = 0; + int j=0; + int sum = 0; + + for(int i=0;i= 31) + { + for(;j<4;j++) + { + src.m_Skin[bonePos].weight[j] = 0; + src.m_Skin[bonePos].boneIndex[j] = 0; + } + bonePos++; + j = 0; + sum = 0; + } + //we read three weights, but they don't add up to one. calculate the fourth one, and read + //missing bone index. continue with next vertex. + else if(j==3) + { + src.m_Skin[bonePos].weight[j] = (31-sum)/31.0; + src.m_Skin[bonePos].boneIndex[j] = boneIndices[boneIndexPos++]; + bonePos++; + j = 0; + sum = 0; + } + } + + delete[] weights; + delete[] boneIndices; + } +} + +template void CompressedAnimationCurve::CompressTimeKeys(AnimationCurveTpl &src) +{ + int numKeys = src.GetKeyCount(); + + float minTime=0; + for(int i=0;i void CompressedAnimationCurve::DecompressTimeKeys(AnimationCurveTpl &src) +{ + int numKeys = m_Times.Count(); + UInt32 *times = new UInt32[numKeys]; + m_Times.UnpackInts(times); + + UInt32 t=0; + + src.ResizeUninitialized(numKeys); + + for(int i=0;i