aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/module/clothing/src/ClothingAssetData.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/module/clothing/src/ClothingAssetData.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'APEX_1.4/module/clothing/src/ClothingAssetData.cpp')
-rw-r--r--APEX_1.4/module/clothing/src/ClothingAssetData.cpp874
1 files changed, 874 insertions, 0 deletions
diff --git a/APEX_1.4/module/clothing/src/ClothingAssetData.cpp b/APEX_1.4/module/clothing/src/ClothingAssetData.cpp
new file mode 100644
index 00000000..795e0f04
--- /dev/null
+++ b/APEX_1.4/module/clothing/src/ClothingAssetData.cpp
@@ -0,0 +1,874 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include "ApexSimdMath.h"
+#include "PxPreprocessor.h"
+#include "RenderDataFormat.h"
+#include "ClothingAssetData.h"
+#include "PsIntrinsics.h"
+#include "PsVecMath.h"
+#include "PxMat44.h"
+
+#define NX_PARAMETERIZED_ONLY_LAYOUTS
+#include "ClothingGraphicalLodParameters.h"
+
+#pragma warning(disable : 4101 4127) // unreferenced local variable and conditional expression is constant
+
+
+namespace nvidia
+{
+using namespace physx::shdfnd;
+//using namespace physx::shdfnd::aos;
+
+namespace clothing
+{
+
+ClothingAssetSubMesh::ClothingAssetSubMesh() :
+ mPositions(NULL),
+ mNormals(NULL),
+ mTangents(NULL),
+ mBoneWeights(NULL),
+ mBoneIndices(NULL),
+ mIndices(NULL),
+ mUvs(NULL),
+
+ mPositionOutFormat(RenderDataFormat::UNSPECIFIED),
+ mNormalOutFormat(RenderDataFormat::UNSPECIFIED),
+ mTangentOutFormat(RenderDataFormat::UNSPECIFIED),
+ mBoneWeightOutFormat(RenderDataFormat::UNSPECIFIED),
+ mUvFormat(RenderDataFormat::UNSPECIFIED),
+
+ mVertexCount(0),
+ mIndicesCount(0),
+ mUvCount(0),
+ mNumBonesPerVertex(0),
+
+ mCurrentMaxVertexSimulation(0),
+ mCurrentMaxVertexAdditionalSimulation(0),
+ mCurrentMaxIndexSimulation(0)
+{
+}
+
+
+
+ClothingMeshAssetData::ClothingMeshAssetData() :
+ mImmediateClothMap(NULL),
+ mSkinClothMap(NULL),
+ mSkinClothMapB(NULL),
+ mTetraMap(NULL),
+
+ mImmediateClothMapCount(0),
+ mSkinClothMapCount(0),
+ mSkinClothMapBCount(0),
+ mTetraMapCount(0),
+
+ mSubmeshOffset(0),
+ mSubMeshCount(0),
+
+ mPhysicalMeshId(0),
+
+ mSkinClothMapThickness(0.0f),
+ mSkinClothMapOffset(0.0f),
+
+ mBounds(PxBounds3::empty()),
+
+ bActive(false)
+{
+
+}
+
+
+
+ClothingPhysicalMeshData::ClothingPhysicalMeshData() :
+ mVertices(NULL),
+ mVertexCount(0),
+ mSimulatedVertexCount(0),
+ mMaxDistance0VerticesCount(0),
+ mNormals(NULL),
+ mSkinningNormals(NULL),
+ mBoneIndices(NULL),
+ mBoneWeights(NULL),
+ mOptimizationData(NULL),
+ mIndices(NULL),
+
+ mSkinningNormalsCount(0),
+ mBoneWeightsCount(0),
+ mOptimizationDataCount(0),
+ mIndicesCount(0),
+ mSimulatedIndicesCount(0),
+
+ mNumBonesPerVertex(0)
+{
+
+}
+
+
+
+ClothingAssetData::ClothingAssetData() :
+ mData(NULL),
+ mCompressedNumBonesPerVertex(NULL),
+ mCompressedTangentW(NULL),
+ mExt2IntMorphMapping(NULL),
+ mCompressedNumBonesPerVertexCount(0),
+ mCompressedTangentWCount(0),
+ mExt2IntMorphMappingCount(0),
+
+ mAssetSize(0),
+ mGraphicalLodsCount(0),
+ mPhysicalMeshesCount(0),
+ mPhysicalMeshOffset(0),
+ mBoneCount(0),
+ mRootBoneIndex(0)
+{
+
+}
+
+
+
+
+ClothingAssetData::~ClothingAssetData()
+{
+ PX_FREE(mData);
+ mData = NULL;
+}
+
+
+
+void ClothingAssetData::skinToBones(AbstractMeshDescription& destMesh, uint32_t submeshIndex, uint32_t graphicalMeshIndex, uint32_t startVertex,
+ PxMat44* compositeMatrices, PxVec3* morphDisplacements)
+{
+ // This is no nice code, but it allows to have 8 different code paths through skinToBones that have all the if's figured out at compile time (hopefully)
+ PX_ASSERT(destMesh.pTangent == NULL);
+ PX_ASSERT(destMesh.pBitangent == NULL);
+
+ if (destMesh.pNormal != NULL)
+ {
+ if (mBoneCount != 0)
+ {
+ if (morphDisplacements != NULL)
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<true, true, true, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<true, true, true, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ else
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<true, true, false, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<true, true, false, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ }
+ else
+ {
+ if (morphDisplacements != NULL)
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<true, false, true, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<true, false, true, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ else
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<true, false, false, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<true, false, false, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (mBoneCount != 0)
+ {
+ if (morphDisplacements != NULL)
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<false, true, true, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<false, true, true, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ else
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<false, true, false, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<false, true, false, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ }
+ else
+ {
+ if (morphDisplacements != NULL)
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<false, false, true, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<false, false, true, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ else
+ {
+ if (destMesh.pTangent4 != NULL)
+ {
+ skinToBonesInternal<false, false, false, true>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ else
+ {
+ skinToBonesInternal<false, false, false, false>(destMesh, submeshIndex, graphicalMeshIndex, startVertex, compositeMatrices, morphDisplacements);
+ }
+ }
+ }
+ }
+}
+
+
+template<bool withNormals, bool withBones, bool withMorph, bool withTangents>
+void ClothingAssetData::skinToBonesInternal(AbstractMeshDescription& destMesh, uint32_t submeshIndex, uint32_t graphicalMeshIndex,
+ uint32_t startVertex, PxMat44* compositeMatrices, PxVec3* morphDisplacements)
+{
+ PX_ASSERT(withNormals == (destMesh.pNormal != NULL));
+ PX_ASSERT(withMorph == (morphDisplacements != NULL));
+
+ PX_ASSERT(withTangents == (destMesh.pTangent4 != NULL));
+ PX_ASSERT(destMesh.pTangent == NULL);
+ PX_ASSERT(destMesh.pBitangent == NULL);
+
+ // so we need to start further behind, but to make vec3* still aligned it must be a multiple of 4, and to make
+ // compressedNumBones aligned, it needs to be a multiple of 16 (hence 16)
+ // The start offset is reduced by up to 16, and instead of skipping the first [0, 16) vertices and adding additional logic
+ // they just get computed as well, assuming much less overhead than an additional if in the innermost loop
+ // Note: This only works if the mesh-mesh skinning is executed afterwards!
+ const uint32_t startVertex16 = startVertex - (startVertex % 16);
+
+ PX_ASSERT(((size_t)(compositeMatrices) & 0xf) == 0); // make sure the pointer is 16 byte aligned!!
+
+ ClothingMeshAssetData* meshAsset = GetLod(graphicalMeshIndex);
+ PX_ASSERT(submeshIndex < meshAsset->mSubMeshCount);
+ ClothingAssetSubMesh* pSubmesh = GetSubmesh(meshAsset, submeshIndex);
+ const uint32_t numVertices = pSubmesh->mVertexCount - startVertex16;
+ if(numVertices == 0)
+ {
+ return;
+ }
+
+ // use the per-asset setting
+ const uint32_t startVertexDiv16 = startVertex16 / 16;
+ uint32_t mapSize = 0;
+ const uint32_t* compressedNumBonesPerVertexEa = getCompressedNumBonesPerVertex(graphicalMeshIndex, submeshIndex, mapSize);
+ PX_ASSERT((mapSize - startVertexDiv16) * 16 >= numVertices);
+
+ const uint32_t* compressedNumBonesPerVertex = (const uint32_t*)((uint32_t*)compressedNumBonesPerVertexEa + startVertexDiv16);
+
+ const PxVec3* PX_RESTRICT positionsEa = pSubmesh->mPositions + startVertex16;
+ PX_ASSERT(pSubmesh->mPositionOutFormat == RenderDataFormat::FLOAT3);
+ const PxVec3* PX_RESTRICT normalsEa = pSubmesh->mNormals + startVertex16;
+ PX_ASSERT(pSubmesh->mNormalOutFormat == RenderDataFormat::FLOAT3);
+
+ const PxVec4* PX_RESTRICT tangentsEa = pSubmesh->mTangents + (pSubmesh->mTangents != NULL ? startVertex16 : 0);
+ PX_ASSERT(tangentsEa == NULL || pSubmesh->mTangentOutFormat == RenderDataFormat::FLOAT4);
+
+ //These are effective addresses (ea)
+ PxVec3* PX_RESTRICT destPositionsEa = destMesh.pPosition + startVertex16;
+ PxVec3* PX_RESTRICT destNormalsEa = destMesh.pNormal + startVertex16;
+ PxVec4* PX_RESTRICT destTangentsEa = (destMesh.pTangent4 != NULL) ? destMesh.pTangent4 + startVertex16 : NULL;
+
+ uint32_t* morphReorderingEa = morphDisplacements != NULL ? getMorphMapping(graphicalMeshIndex) : NULL;
+ if (morphReorderingEa != NULL)
+ {
+ morphReorderingEa += startVertex16;
+ }
+ else if (withMorph)
+ {
+ // actually we don't have a morph map, so let's take one step back
+ skinToBonesInternal<withNormals, withBones, false, withTangents>(destMesh, submeshIndex, graphicalMeshIndex,
+ startVertex, compositeMatrices, NULL);
+ return;
+ }
+ PX_ASSERT((morphDisplacements != NULL) == (morphReorderingEa != NULL));
+
+ const uint16_t* PX_RESTRICT boneIndicesEa = NULL;
+ const float* PX_RESTRICT boneWeightsEa = NULL;
+
+ const uint32_t maxNumBonesPerVertex = pSubmesh->mNumBonesPerVertex;
+ if (withBones)
+ {
+ boneIndicesEa = (const uint16_t*)pSubmesh->mBoneIndices + (startVertex16 * maxNumBonesPerVertex);
+ boneWeightsEa = (const float*)pSubmesh->mBoneWeights + (startVertex16 * maxNumBonesPerVertex);
+ }
+
+
+ //bones per vertex is LS address!!!!
+ const uint32_t* PX_RESTRICT bonesPerVertex = compressedNumBonesPerVertex;
+
+ //OK. Need to split this up into an even larger subset of work!!!! Perhaps sets of 1024 vertices/normals/bones....
+
+ const uint32_t WorkSize = 160;
+
+ const uint32_t countWork = (numVertices + (WorkSize - 1)) / WorkSize;
+
+ for (uint32_t a = 0; a < countWork; ++a)
+ {
+ const uint32_t workCount = PxMin(numVertices - (a * WorkSize), WorkSize);
+
+ const PxVec3* PX_RESTRICT positions = (const PxVec3 * PX_RESTRICT)(void*)positionsEa;
+ const PxVec3* PX_RESTRICT normals = NULL;
+ const float* PX_RESTRICT tangents4 = NULL;
+ const uint16_t* PX_RESTRICT boneIndices = NULL;
+ const float* PX_RESTRICT boneWeights = NULL;
+
+ PxVec3* PX_RESTRICT destPositions = (PxVec3 * PX_RESTRICT)(void*)destPositionsEa;
+ PxVec3* PX_RESTRICT destNormals = NULL;
+ float* PX_RESTRICT destTangents4 = NULL;
+
+ uint32_t* morphReordering = NULL;
+ if (withMorph)
+ {
+ morphReordering = (uint32_t*)morphReorderingEa;
+ morphReorderingEa += workCount;
+ }
+
+ if (withBones)
+ {
+ boneIndices = (const uint16_t * PX_RESTRICT)(void*)boneIndicesEa;
+ boneWeights = (const float * PX_RESTRICT)(void*)boneWeightsEa;
+ }
+
+ if (withNormals)
+ {
+ destNormals = (PxVec3 * PX_RESTRICT)(void*)destNormalsEa;
+ normals = (const PxVec3 * PX_RESTRICT)(void*)normalsEa;
+ }
+
+ if (withTangents)
+ {
+ destTangents4 = (float*)(void*)destTangentsEa;
+ tangents4 = (const float*)(void*)tangentsEa;
+ }
+
+
+ const uint32_t count16 = (workCount + 15) / 16;
+ for (uint32_t i = 0; i < count16; ++i)
+ {
+ //Fetch in the next block of stuff...
+ const uint32_t maxVerts = PxMin(numVertices - (a * WorkSize) - (i * 16u), 16u);
+ uint32_t numBoneWeight = *bonesPerVertex++;
+
+ prefetchLine(positions + 16);
+
+ if (withNormals)
+ {
+ prefetchLine(normals + 16);
+ }
+
+ if (withBones)
+ {
+ prefetchLine(boneIndices + (4 * 16));
+ prefetchLine(boneWeights + (2 * 16));
+ prefetchLine(boneWeights + (4 * 16));
+ }
+
+ if (withTangents)
+ {
+ prefetchLine(tangents4 + (4 * 16));
+ }
+
+ for (uint32_t j = 0; j < maxVerts; j++)
+ {
+ const uint32_t vertexIndex = i * 16 + j;
+ const uint32_t numBones = (numBoneWeight & 0x3) + 1;
+ numBoneWeight >>= 2;
+
+ {
+ PxVec3 untransformedPosition = *positions;
+ if (withMorph)
+ {
+ const PxVec3* morphDisplacement = (PxVec3*)&morphDisplacements[morphReordering[vertexIndex]];
+ untransformedPosition += *morphDisplacement;
+ }
+ Simd4f positionV = gSimd4fZero;
+ Simd4f normalV = gSimd4fZero;
+ Simd4f tangentV = gSimd4fZero;
+
+ if (withBones)
+ {
+ for (uint32_t k = 0; k < numBones; k++)
+ {
+ float weight = boneWeights[k];
+
+ PX_ASSERT(PxIsFinite(weight));
+
+ const uint16_t boneNr = boneIndices[k];
+
+ PxMat44& skinningMatrixV = (PxMat44&)compositeMatrices[boneNr];
+
+ const Simd4f weightV = Simd4fScalarFactory(weight);
+
+ Simd4f transformedPositionV = applyAffineTransform(skinningMatrixV, createSimd3f(untransformedPosition));
+ transformedPositionV = transformedPositionV * weightV;
+ positionV = positionV + transformedPositionV;
+
+ if (withNormals)
+ {
+ Simd4f transformedNormalV = applyLinearTransform(skinningMatrixV, createSimd3f(*normals));
+ transformedNormalV = transformedNormalV * weightV;
+ normalV = normalV + transformedNormalV;
+ }
+
+ if (withTangents)
+ {
+ const Simd4f inTangent = Simd4fAlignedLoadFactory(tangents4);
+ const Simd4f transformedTangentV = applyLinearTransform(skinningMatrixV, inTangent);
+ tangentV = tangentV + transformedTangentV * weightV;
+ }
+ }
+ }
+ else
+ {
+ PxMat44& skinningMatrixV = (PxMat44&)compositeMatrices[0];
+ positionV = applyAffineTransform(skinningMatrixV, createSimd3f(untransformedPosition));
+ if (withNormals)
+ {
+ normalV = applyLinearTransform(skinningMatrixV, createSimd3f(*normals));
+ }
+ if (withTangents)
+ {
+ const Simd4f inTangent = Simd4fAlignedLoadFactory(tangents4);
+ tangentV = applyLinearTransform(skinningMatrixV, inTangent);
+ }
+
+ }
+
+ if (withNormals)
+ {
+ normalV = normalizeSimd3f(normalV);
+ store3(&(destNormals->x), normalV);
+ }
+
+
+ if (withTangents)
+ {
+ tangentV = normalizeSimd3f(tangentV);
+ const Simd4f bitangent = Simd4fScalarFactory(tangents4[3]);
+ const Simd4f outTangent = select(gSimd4fMaskXYZ, tangentV, bitangent);
+ storeAligned(destTangents4, outTangent);
+ }
+
+ // if all weights are 0, we use the bind pose
+ // we don't really need that and it just slows us down..
+ //*destPositions = (numBones == 0) ? *positions : ps;
+ //*destPositions = ps;
+ store3(&destPositions->x, positionV);
+ }
+
+ positions++;
+ positionsEa++;
+ normals++;
+ normalsEa++;
+ if (withBones)
+ {
+ boneWeights += maxNumBonesPerVertex;
+ boneWeightsEa += maxNumBonesPerVertex;
+ boneIndices += maxNumBonesPerVertex;
+ boneIndicesEa += maxNumBonesPerVertex;
+ }
+ if (withTangents)
+ {
+ tangents4 += 4;
+ tangentsEa++;
+ destTangents4 += 4;
+ destTangentsEa++;
+ }
+ destPositions++;
+ destPositionsEa++;
+ destNormals++;
+ destNormalsEa++;
+ }
+ }
+ }
+
+}
+
+
+
+uint32_t* ClothingAssetData::getMorphMapping(uint32_t graphicalLod)
+{
+ if (mExt2IntMorphMappingCount == 0)
+ {
+ return NULL;
+ }
+
+ if (graphicalLod == (uint32_t) - 1 || graphicalLod > mGraphicalLodsCount)
+ {
+ graphicalLod = mGraphicalLodsCount;
+ }
+
+ uint32_t offset = 0;
+ for (uint32_t i = 0; i < graphicalLod; i++)
+ {
+ const ClothingMeshAssetData* meshAsset = GetLod(i);
+ for (uint32_t s = 0; s < meshAsset->mSubMeshCount; s++)
+ {
+ offset += GetSubmesh(meshAsset, s)->mVertexCount;
+ }
+ }
+
+ PX_ASSERT(offset < mExt2IntMorphMappingCount);
+ return mExt2IntMorphMapping + offset;
+}
+
+
+
+const uint32_t* ClothingAssetData::getCompressedNumBonesPerVertex(uint32_t graphicalLod, uint32_t submeshIndex, uint32_t& mapSize)
+{
+ mapSize = 0;
+
+ uint32_t offset = 0;
+ for (uint32_t lodIndex = 0; lodIndex < mGraphicalLodsCount; lodIndex++)
+ {
+ const ClothingMeshAssetData* meshAsset = GetLod(lodIndex);
+
+ for (uint32_t s = 0; s < meshAsset->mSubMeshCount; s++)
+ {
+ const uint32_t numVertices = GetSubmesh(meshAsset, s)->mVertexCount;
+
+ uint32_t numEntries = (numVertices + 15) / 16;
+ while ((numEntries & 0x3) != 0) // this is a numEntries % 4
+ {
+ numEntries++;
+ }
+
+ if (lodIndex == graphicalLod && submeshIndex == s)
+ {
+ mapSize = numEntries;
+ PX_ASSERT((mapSize % 4) == 0);
+ return &mCompressedNumBonesPerVertex[offset];
+ }
+
+ offset += numEntries;
+ PX_ASSERT(mCompressedNumBonesPerVertexCount >= offset);
+ }
+ }
+ return NULL;
+}
+
+
+
+const uint32_t* ClothingAssetData::getCompressedTangentW(uint32_t graphicalLod, uint32_t submeshIndex, uint32_t& mapSize)
+{
+ mapSize = 0;
+
+ uint32_t offset = 0;
+ for (uint32_t lodIndex = 0; lodIndex < mGraphicalLodsCount; lodIndex++)
+ {
+ const ClothingMeshAssetData* meshAsset = GetLod(lodIndex);
+
+ for (uint32_t s = 0; s < meshAsset->mSubMeshCount; s++)
+ {
+ const uint32_t numVertices = GetSubmesh(meshAsset, s)->mVertexCount;
+
+ uint32_t numEntries = (numVertices + 31) / 32;
+ while ((numEntries & 0x3) != 0) // this is a numEntries % 4
+ {
+ numEntries++;
+ }
+
+ if (lodIndex == graphicalLod && submeshIndex == s)
+ {
+ mapSize = numEntries;
+ PX_ASSERT((mapSize % 4) == 0);
+ return (uint32_t*)&mCompressedTangentW[offset];
+ }
+
+ offset += numEntries;
+ PX_ASSERT(mCompressedTangentWCount >= offset);
+ }
+ }
+ return NULL;
+}
+
+
+
+void ClothingAssetData::getNormalsAndVerticesForFace(PxVec3* vtx, PxVec3* nrm, uint32_t i,
+ const AbstractMeshDescription& srcPM) const
+{
+ // copy indices for convenience
+ PX_ASSERT(i < srcPM.numIndices);
+ uint32_t di[3];
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ di[j] = srcPM.pIndices[i + j];
+ }
+
+ // To guarantee consistency in our implicit tetrahedral mesh definition we must always order vertices
+ // idx[0,1,2] = min, max and mid
+ uint32_t idx[3];
+ idx[0] = PxMin(di[0], PxMin(di[1], di[2]));
+ idx[1] = PxMax(di[0], PxMax(di[1], di[2]));
+ idx[2] = idx[0];
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ if ((idx[0] != di[j]) && (idx[1] != di[j]))
+ {
+ idx[2] = di[j];
+ }
+ }
+
+ for (uint32_t j = 0; j < 3; j++)
+ {
+ vtx[j] = srcPM.pPosition[idx[j]];
+ nrm[j] = srcPM.pNormal[idx[j]];
+#ifdef _DEBUG
+ // sanity
+ // PH: These normals 'should' always be normalized, maybe we can get rid of the normalize completely!
+ const float length = nrm[j].magnitudeSquared();
+ if (!(length >= 0.99f && length <= 1.01f))
+ {
+ static bool first = true;
+ if (first)
+ {
+ PX_ALWAYS_ASSERT();
+ first = false;
+ }
+ }
+#else
+ // PH: let's try and disable it in release mode...
+ //nrm[j].normalize();
+#endif
+ };
+}
+
+
+uint32_t ClothingAssetData::skinClothMapBSkinVertex(PxVec3& dstPos, PxVec3* dstNormal, uint32_t vIndex,
+ ClothingGraphicalLodParametersNS::SkinClothMapB_Type* pTCMB, const ClothingGraphicalLodParametersNS::SkinClothMapB_Type* pTCMBEnd,
+ const AbstractMeshDescription& srcPM) const
+{
+ uint32_t numIterations(0);
+ //uint32_t numSkipped(0);
+
+ //PX_ASSERT(dstPos.isZero());
+ //PX_ASSERT(dstNormal == NULL || dstNormal->isZero());
+
+ PX_ASSERT(srcPM.avgEdgeLength != 0.0f);
+ const float pmThickness = srcPM.avgEdgeLength;
+
+ while ((pTCMB->vertexIndexPlusOffset == vIndex) && (pTCMB < pTCMBEnd))
+ {
+ // skip vertices that we couldn't find a binding for
+ if (pTCMB->faceIndex0 == 0xFFFFFFFF || pTCMB->faceIndex0 >= srcPM.numIndices)
+ {
+ pTCMB++;
+ //numSkipped++;
+ //numIterations++;
+ continue;
+ }
+
+ PxVec3 vtx[3], nrm[3];
+ getNormalsAndVerticesForFace(vtx, nrm, pTCMB->faceIndex0, srcPM);
+
+ const TetraEncoding_Local& tetEnc = tetraTableLocal[pTCMB->tetraIndex];
+ const PxVec3 tv0 = vtx[0] + (tetEnc.sign[0] * pmThickness) * nrm[0];
+ const PxVec3 tv1 = vtx[1] + (tetEnc.sign[1] * pmThickness) * nrm[1];
+ const PxVec3 tv2 = vtx[2] + (tetEnc.sign[2] * pmThickness) * nrm[2];
+ const PxVec3 tv3 = vtx[tetEnc.lastVtxIdx] + (tetEnc.sign[3] * pmThickness) * nrm[tetEnc.lastVtxIdx];
+
+ const PxVec3& vtb = pTCMB->vtxTetraBary;
+ const float vtbw = 1.0f - vtb.x - vtb.y - vtb.z;
+ dstPos = (vtb.x * tv0) + (vtb.y * tv1) + (vtb.z * tv2) + (vtbw * tv3);
+ PX_ASSERT(dstPos.isFinite());
+
+ if (dstNormal != NULL)
+ {
+ const PxVec3& ntb = pTCMB->nrmTetraBary;
+ const float ntbw = 1.0f - ntb.x - ntb.y - ntb.z;
+ *dstNormal = (ntb.x * tv0) + (ntb.y * tv1) + (ntb.z * tv2) + (ntbw * tv3);
+ PX_ASSERT(dstNormal->isFinite());
+ }
+
+ pTCMB++;
+ numIterations++;
+ }
+
+ if (dstNormal != NULL && numIterations > 0)
+ {
+ // PH: this code certainly does not work if numIterations is bigger than 1 (it would need to average by dividing through numIterations)
+ PX_ASSERT(numIterations == 1);
+ *dstNormal -= dstPos;
+ *dstNormal *= physx::shdfnd::recipSqrtFast(dstNormal->magnitudeSquared());
+ }
+
+ return numIterations;
+}
+
+
+uint32_t ClothingAssetData::skinClothMapB(PxVec3* dstPositions, PxVec3* dstNormals, uint32_t numVertices,
+ const AbstractMeshDescription& srcPM, ClothingGraphicalLodParametersNS::SkinClothMapB_Type* map,
+ uint32_t numVerticesInMap, bool computeNormals) const
+{
+ PX_ASSERT(srcPM.numIndices % 3 == 0);
+
+ PX_ASSERT(srcPM.avgEdgeLength != 0.0f);
+
+ ClothingGraphicalLodParametersNS::SkinClothMapB_Type* pTCMB = map;
+ ClothingGraphicalLodParametersNS::SkinClothMapB_Type* pTCMBEnd = map + numVerticesInMap;
+
+ for (uint32_t j = 0; j < numVerticesInMap; j++)
+ {
+ uint32_t vertexIndex = pTCMB->vertexIndexPlusOffset;
+
+ if (vertexIndex >= numVertices)
+ {
+ pTCMB++;
+ continue;
+ }
+
+ PxVec3& p = dstPositions[vertexIndex];
+
+ PxVec3* n = NULL;
+ if (computeNormals)
+ {
+ n = dstNormals + vertexIndex;
+ }
+
+ uint32_t numIters = skinClothMapBSkinVertex(p, n, vertexIndex, pTCMB, pTCMBEnd, srcPM);
+ if (numIters == 0)
+ {
+ // PH: find next submesh
+ const uint32_t currentIterations = (uint32_t)(size_t)(pTCMB - map);
+ for (uint32_t i = currentIterations; i < numVerticesInMap; i++)
+ {
+ if (map[i].submeshIndex > pTCMB->submeshIndex)
+ {
+ numIters = i - currentIterations;
+ break;
+ }
+ }
+
+ // only return if it's still 0
+ if (numIters == 0)
+ {
+ return currentIterations;
+ }
+ }
+
+ pTCMB += numIters;
+ }
+
+ return numVertices;
+}
+
+bool ClothingAssetData::skinToTetraMesh(AbstractMeshDescription& destMesh,
+ const AbstractMeshDescription& srcPM,
+ const ClothingMeshAssetData& graphicalLod)
+{
+ if (graphicalLod.mTetraMap == NULL)
+ {
+ return false;
+ }
+
+ PX_ASSERT(srcPM.numIndices % 4 == 0);
+
+ PX_ASSERT(destMesh.pIndices == NULL);
+ PX_ASSERT(destMesh.pTangent == NULL);
+ PX_ASSERT(destMesh.pBitangent == NULL);
+ const bool computeNormals = destMesh.pNormal != NULL;
+
+ PxVec3 dummyNormal;
+
+ const uint32_t numGraphicalVertices = destMesh.numVertices;
+
+ const uint32_t* mainIndices = GetPhysicalMesh(graphicalLod.mPhysicalMeshId)->mIndices;
+
+ for (uint32_t i = 0; i < numGraphicalVertices; i++)
+ {
+ const ClothingGraphicalLodParametersNS::TetraLink_Type& currentLink = graphicalLod.mTetraMap[i];
+ if (currentLink.tetraIndex0 >= srcPM.numIndices)
+ {
+ continue;
+ }
+
+ PxVec3& position = destMesh.pPosition[i];
+ position = PxVec3(0.0f);
+
+ float vertexBary[4];
+ vertexBary[0] = currentLink.vertexBary.x;
+ vertexBary[1] = currentLink.vertexBary.y;
+ vertexBary[2] = currentLink.vertexBary.z;
+ vertexBary[3] = 1 - vertexBary[0] - vertexBary[1] - vertexBary[2];
+
+ const uint32_t* indices = mainIndices + currentLink.tetraIndex0;
+
+ if (computeNormals)
+ {
+ PxVec3& normal = computeNormals ? destMesh.pNormal[i] : dummyNormal;
+ normal = PxVec3(0.0f);
+
+ float normalBary[4];
+ normalBary[0] = currentLink.normalBary.x;
+ normalBary[1] = currentLink.normalBary.y;
+ normalBary[2] = currentLink.normalBary.z;
+ normalBary[3] = 1 - normalBary[0] - normalBary[1] - normalBary[2];
+
+ // compute skinned positions and normals
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ const PxVec3& pos = srcPM.pPosition[indices[j]];
+ position += pos * vertexBary[j];
+ normal += pos * normalBary[j];
+ }
+
+ normal = normal - position;
+ normal *= nvidia::recipSqrtFast(normal.magnitudeSquared());
+ }
+ else
+ {
+ // only compute skinned positions, not normals
+ for (uint32_t j = 0; j < 4; j++)
+ {
+ const PxVec3& pos = srcPM.pPosition[indices[j]];
+ position += pos * vertexBary[j];
+ }
+ }
+ PX_ASSERT(position.isFinite());
+ }
+ return true;
+}
+
+
+
+}
+}