There are 3 issues
I found a solution. But it needs additinal functions in NvCloth.
[Link Removed]
[Link Removed]
// code placeholder void FClothingSimulationNv::UpdateLod(int32 InPredictedLod, const FTransform& ComponentToWorld, const TArray<FTransform>& CSTransforms, bool bForceNoRemap, bool bForceActorChecks) ... if(bOldLodMapped && !bForceNoRemap) { FClothingActorNv::FActorLodData& CurrLodData = Actor.LodData[OldClothingLod]; // the number of LODs we've passed through, we can only reskin the incoming mesh if we've stepped 1 LOD const int32 NumLodsPassed = FMath::Abs(OldClothingLod - PredictedClothingLod); const uint32 NumOldParticles = CurrLodData.Cloth->getNumParticles(); nv::cloth::Range<const physx::PxVec4> OldLodParticles = nv::cloth::readCurrentParticles(*CurrLodData.Cloth); #if 1 //fix part 1 : restore previous particle locations nv::cloth::Range<const physx::PxVec4> OldLodPreviousParticles = nv::cloth::readPreviousParticles(*CurrLodData.Cloth); #endif // Remove the old LOD from the solver Solver->removeCloth(Actor.LodData[OldClothingLod].Cloth); nv::cloth::Range<physx::PxVec4> OldAccelerations = CurrLodData.Cloth->getParticleAccelerations(); Solver->addCloth(Actor.LodData[PredictedClothingLod].Cloth); if(NumLodsPassed == 1) { // Reposition particles skinned to outgoing LOD bool bLodTransitionUp = OldClothingLod < PredictedClothingLod; FClothLODData& NewLodAssetData = Actor.AssetCreatedFrom->LodData[PredictedClothingLod]; TArray<FMeshToMeshVertData>& SkinData = bLodTransitionUp ? NewLodAssetData.TransitionUpSkinData : NewLodAssetData.TransitionDownSkinData; for(int32 ParticleIndex = 0; ParticleIndex < NumNewParticles; ++ParticleIndex) { // Do some simple skinning, we only care about positions for this as particles are just // positions inside the solver. FMeshToMeshVertData& VertData = SkinData[ParticleIndex]; const FVector A = P2UVector(OldLodParticles[VertData.SourceMeshVertIndices[0]]); const FVector B = P2UVector(OldLodParticles[VertData.SourceMeshVertIndices[1]]); const FVector C = P2UVector(OldLodParticles[VertData.SourceMeshVertIndices[2]]); #if 1 const FVector PA = P2UVector(OldLodPreviousParticles[VertData.SourceMeshVertIndices[0]]); const FVector PB = P2UVector(OldLodPreviousParticles[VertData.SourceMeshVertIndices[1]]); const FVector PC = P2UVector(OldLodPreviousParticles[VertData.SourceMeshVertIndices[2]]); #endif // CurrentNormals still contains the normals from the old LOD, which will have been // calculated at the end of the last simulation step. const FVector& NA = Actor.CurrentNormals[VertData.SourceMeshVertIndices[0]]; const FVector& NB = Actor.CurrentNormals[VertData.SourceMeshVertIndices[1]]; const FVector& NC = Actor.CurrentNormals[VertData.SourceMeshVertIndices[2]]; const physx::PxVec4& AA = OldAccelerations[VertData.SourceMeshVertIndices[0]]; const physx::PxVec4& AB = OldAccelerations[VertData.SourceMeshVertIndices[1]]; const physx::PxVec4& AC = OldAccelerations[VertData.SourceMeshVertIndices[2]]; #if 1 const FVector FinalPosition = VertData.PositionBaryCoordsAndDist.X * A + NA * VertData.PositionBaryCoordsAndDist.W + VertData.PositionBaryCoordsAndDist.Y * B + NB * VertData.PositionBaryCoordsAndDist.W + VertData.PositionBaryCoordsAndDist.Z * C + NC * VertData.PositionBaryCoordsAndDist.W; const FVector FinalPreviousPosition = VertData.PositionBaryCoordsAndDist.X * PA + NA * VertData.PositionBaryCoordsAndDist.W + VertData.PositionBaryCoordsAndDist.Y * PB + NB * VertData.PositionBaryCoordsAndDist.W + VertData.PositionBaryCoordsAndDist.Z * PC + NC * VertData.PositionBaryCoordsAndDist.W; #else FVector FinalPosition = VertData.PositionBaryCoordsAndDist.X * A + NA * VertData.PositionBaryCoordsAndDist.W + VertData.PositionBaryCoordsAndDist.Y * B + NB * VertData.PositionBaryCoordsAndDist.W + VertData.PositionBaryCoordsAndDist.Z * C + NC * VertData.PositionBaryCoordsAndDist.W; #endif physx::PxVec4 FinalAcceleration = VertData.PositionBaryCoordsAndDist.X * AA + VertData.PositionBaryCoordsAndDist.Y * AB + VertData.PositionBaryCoordsAndDist.Z * AC; NewLodParticles[ParticleIndex] = physx::PxVec4(U2PVector(FinalPosition), NewLodParticles[ParticleIndex].w); #if 1 NewLodPrevParticles[ParticleIndex] = physx::PxVec4(U2PVector(FinalPreviousPosition), NewLodParticles[ParticleIndex].w); #else NewLodPrevParticles[ParticleIndex] = physx::PxVec4(U2PVector(FinalPosition), NewLodParticles[ParticleIndex].w); #endif NewAccelerations[ParticleIndex] = FinalAcceleration; } } else { // We've passed more than one LOD, and we don't have transition data for all permutations, just use ref pose for(int32 ParticleIndex = 0; ParticleIndex < NumNewParticles; ++ParticleIndex) { NewLodParticles[ParticleIndex] = NewLodData.Px_RestPositions[ParticleIndex]; NewLodPrevParticles[ParticleIndex] = NewLodData.Px_RestPositions[ParticleIndex]; NewAccelerations[ParticleIndex] = physx::PxVec4(0.0f); } } #if 1 //fix part 2 : store transform from a last cloth instance instead current transform NewLodData.Cloth->setTranslation(CurrLodData.Cloth->getTranslation()); NewLodData.Cloth->setRotation(CurrLodData.Cloth->getRotation()); #else FTransform SimRootTransform = CSTransforms[Actor.AssetCreatedFrom->ReferenceBoneIndex] * ComponentToWorld; NewLodData.Cloth->setTranslation(U2PVector(SimRootTransform.GetTranslation())); NewLodData.Cloth->setRotation(U2PQuat(SimRootTransform.GetRotation())); #endif NewLodData.Cloth->clearInertia(); #if 1 //fix part 3 : Add new functions in NvCloth and then call them for restorng LinearVelocity cleared by clearInertica function. NewLodData.Cloth->setLinearVelocity(CurrLodData.Cloth->getLinearVelocity()); NewLodData.Cloth->setAngularVelocity(CurrLodData.Cloth->getAngularVelocity()); #endif Actor.CurrentLodIndex = PredictedClothingLod; } else
Changing cloth LoD with moving skeletal mesh is trigger.
If skeletal mesh has no velocity, This issue will not happen.
[Link Removed]
There's no existing public thread on this issue, so head over to Questions & Answers just mention UE-77100 in the post.
3 |
Component | UE - Simulation - Physics - Character |
---|---|
Affects Versions | 4.22.3 |
Created | Jul 11, 2019 |
---|---|
Resolved | Jul 19, 2019 |
Updated | Jun 30, 2020 |