summaryrefslogtreecommitdiff
path: root/Runtime/Filters/Mesh/MeshSkinningTests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Filters/Mesh/MeshSkinningTests.cpp')
-rw-r--r--Runtime/Filters/Mesh/MeshSkinningTests.cpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/Runtime/Filters/Mesh/MeshSkinningTests.cpp b/Runtime/Filters/Mesh/MeshSkinningTests.cpp
new file mode 100644
index 0000000..407729b
--- /dev/null
+++ b/Runtime/Filters/Mesh/MeshSkinningTests.cpp
@@ -0,0 +1,228 @@
+#include "UnityPrefix.h"
+#include "Configuration/UnityConfigure.h"
+
+#if ENABLE_UNIT_TESTS && UNITY_SUPPORTS_SSE && !UNITY_64
+
+#include "Runtime/Filters/Mesh/MeshSkinning.h"
+#include "External/UnitTest++/src/UnitTest++.h"
+#include "Runtime/Allocator/MemoryMacros.h"
+#include "Runtime/Math/Random/rand.h"
+#include "Runtime/Math/Matrix4x4.h"
+
+bool SkinMeshOptimizedSSE2(SkinMeshInfo& info);
+void SkinMesh(SkinMeshInfo& info);
+
+Vector3f RandomVector3InUnitBox(Rand& rnd)
+{
+ return Vector3f(rnd.GetSignedFloat(),
+ rnd.GetSignedFloat(),
+ rnd.GetSignedFloat());
+}
+
+SUITE (MeshSkinningTests)
+{
+TEST(MeshSkinning_AllFeatures)
+{
+ int failedPositions = 0;
+ int failedNormals = 0;
+ int failedTangents = 0;
+ int failedTangentSigns = 0;
+ int failedVertexCopies = 0;
+
+ const int minVertices = 1;
+ const int maxVertices = 100;
+ const int positionSize = 3*sizeof(float);
+ const int normalSize = 3*sizeof(float);
+ const int tangentSize = 4*sizeof(float);
+ const int maxStride = positionSize + normalSize + tangentSize;
+ const int trailingBytes = 128;
+
+ UInt8 inVertices[maxVertices * maxStride];
+ UInt8 outVerticesRef[maxVertices * maxStride + trailingBytes];
+ UInt8 outVerticesSimd[maxVertices * maxStride + trailingBytes];
+
+ SkinMeshInfo info;
+ memset(&info, 0, sizeof(info));
+ info.inVertices = inVertices;
+ info.vertexCount = minVertices;
+ info.normalOffset = positionSize;
+ info.tangentOffset = positionSize + normalSize;
+
+ // Try a large offset so AABBs don't contain (0,0,0)
+ Vector3f posOffset(-2000, 0, 2000);
+
+ const int numBones = 64;
+ Matrix4x4f *cachedPose;
+ ALLOC_TEMP_ALIGNED(cachedPose, Matrix4x4f, numBones, 32);
+ info.cachedPose = cachedPose;
+ for (int i = 0; i < numBones; i++)
+ {
+ Matrix4x4f mat;
+ mat.SetScale(Vector3f(1.0 + 0.5f*sin(i*0.3f),
+ 1.0 + 0.5f*sin(i*0.5f),
+ 1.0 + 0.5f*sin(i*0.7f)));
+ mat.SetPosition(Vector3f(100.0f*sin(i*1.0f),
+ 100.0f*sin(i*2.5f),
+ 100.0f*sin(i*3.3f)) + posOffset);
+ cachedPose[i] = mat;
+ }
+ info.boneCount = numBones;
+
+ Rand rnd(123);
+
+ int boneIndices[maxVertices];
+ BoneInfluence2 boneInfl2[maxVertices];
+ BoneInfluence boneInfl4[maxVertices];
+ for (int i = 0; i < maxVertices; i++)
+ {
+ boneIndices[i] = i%numBones;
+
+ BoneInfluence2& b2 = boneInfl2[i];
+ b2.boneIndex[0] = (i)%numBones;
+ b2.boneIndex[1] = (i/2+10)%numBones;
+ b2.weight[0] = rnd.GetFloat();
+ b2.weight[1] = 1.0f - b2.weight[0];
+
+ BoneInfluence& b4 = boneInfl4[i];
+ b4.boneIndex[0] = (i)%numBones;
+ b4.boneIndex[1] = (i/2+10)%numBones;
+ b4.boneIndex[2] = (i/3+20)%numBones;
+ b4.boneIndex[3] = (i/4+30)%numBones;
+ float weightLeft = 1.0f;
+ for (int j=0; j<3; j++)
+ {
+ b4.weight[j] = weightLeft * rnd.GetFloat();
+ weightLeft -= b4.weight[j];
+ }
+ b4.weight[3] = weightLeft;
+ }
+
+ for (info.bonesPerVertex = 1; info.bonesPerVertex <= 4; info.bonesPerVertex++)
+ {
+ if (info.bonesPerVertex == 3) continue;
+
+ switch (info.bonesPerVertex)
+ {
+ case 1:
+ info.compactSkin = boneIndices;
+ break;
+ case 2:
+ info.compactSkin = boneInfl2;
+ break;
+ case 4:
+ info.compactSkin = boneInfl4;
+ break;
+ }
+
+ for (int skinNormals = 0; skinNormals <= 1; skinNormals++)
+ {
+ info.skinNormals = (skinNormals != 0);
+
+ for (int skinTangents = 0; skinTangents <= 1; skinTangents++)
+ {
+ if (!skinNormals && skinTangents) continue;
+ info.skinTangents = (skinTangents != 0);
+
+ // Randomize vertex count and stride
+ info.vertexCount += 7;
+ while (info.vertexCount > maxVertices) info.vertexCount -= (maxVertices - minVertices);
+ info.inStride = positionSize;
+ info.inStride += skinNormals ? normalSize : 0;
+ info.inStride += skinTangents ? tangentSize : 0;
+ info.outStride = info.inStride;
+
+ UInt8* inVert = inVertices;
+ for (int i = 0; i < info.vertexCount; i++)
+ {
+ Vector3f* nextVec = (Vector3f*)inVert;
+ Vector3f pos = RandomVector3InUnitBox(rnd);
+ pos *= 1000.0f;
+ *nextVec++ = pos;
+ if (info.skinNormals)
+ {
+ Vector3f normal = RandomVector3InUnitBox(rnd);
+ normal = NormalizeSafe(normal);
+ *nextVec++ = normal;
+ }
+
+ if (info.skinTangents)
+ {
+ Vector3f tangent = RandomVector3InUnitBox(rnd);
+ tangent = NormalizeSafe(tangent);
+ *nextVec++ = tangent;
+ float* tangentSign = (float*)nextVec;
+ *tangentSign = (rnd.GetSignedFloat() < 0.0f) ? -1.0f : 1.0f;
+ }
+ inVert += info.inStride;
+ }
+
+ int outSize = info.vertexCount * info.outStride;
+ memset(outVerticesRef, 0xcc, outSize + trailingBytes);
+ memset(outVerticesSimd, 0xdd, outSize + trailingBytes);
+
+ info.outVertices = outVerticesRef;
+ SkinMesh(info);
+
+ info.outVertices = outVerticesSimd;
+ bool successSimd = SkinMeshOptimizedSSE2(info);
+ CHECK(successSimd);
+
+ // Check if we wrote past end of buffer
+ for (int i = 0; i < trailingBytes; i++)
+ {
+ CHECK_EQUAL(0xcc, outVerticesRef[outSize + i]);
+ CHECK_EQUAL(0xdd, outVerticesSimd[outSize + i]);
+ }
+
+ inVert = inVertices;
+ UInt8* vertRef = outVerticesRef;
+ UInt8* vertSimd = outVerticesSimd;
+ for (int i = 0; i < info.vertexCount; i++)
+ {
+ Vector3f* posRef = (Vector3f*)vertRef;
+ Vector3f* posSimd = (Vector3f*)vertRef;
+ if (!CompareApproximately(*posRef, *posSimd))
+ {
+ failedPositions++;
+ }
+ if (info.skinNormals)
+ {
+ Vector3f* normalRef = (Vector3f*)(vertRef + info.normalOffset);
+ Vector3f* normalSimd = (Vector3f*)(vertRef + info.normalOffset);
+ if (!CompareApproximately(*normalRef, *normalSimd))
+ {
+ failedNormals++;
+ }
+ }
+ if (info.skinTangents)
+ {
+ Vector3f* tangentRef = (Vector3f*)(vertRef + info.tangentOffset);
+ Vector3f* tangentSimd = (Vector3f*)(vertRef + info.tangentOffset);
+ if (!CompareApproximately(*tangentRef, *tangentSimd))
+ {
+ failedTangents++;
+ }
+ float* tangentSignRef = (float*)(vertRef + info.tangentOffset + sizeof(Vector3f));
+ float* tangentSignSimd = (float*)(vertRef + info.tangentOffset + sizeof(Vector3f));
+ if (*tangentSignRef != *tangentSignSimd)
+ {
+ failedTangentSigns++;
+ }
+ }
+
+ inVert += info.inStride;
+ vertRef += info.outStride;
+ vertSimd += info.outStride;
+ }
+ }
+ }
+ }
+
+ CHECK_EQUAL(0, failedPositions);
+ CHECK_EQUAL(0, failedNormals);
+ CHECK_EQUAL(0, failedTangents);
+ CHECK_EQUAL(0, failedTangentSigns);
+ CHECK_EQUAL(0, failedVertexCopies);
+}
+}
+#endif