void UPoseableMeshComponent::FillSpaceBases()
{
	SCOPE_CYCLE_COUNTER(STAT_SkelComposeTime);

	if( !SkeletalMesh )
	{
		return;
	}

	// right now all this does is to convert to SpaceBases
	check( SkeletalMesh->RefSkeleton.GetNum() == LocalAtoms.Num() );
	check( SkeletalMesh->RefSkeleton.GetNum() == GetNumSpaceBases());
	check( SkeletalMesh->RefSkeleton.GetNum() == BoneVisibilityStates.Num() );

	const int32 NumBones = LocalAtoms.Num();

#if (UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT)
	/** Keep track of which bones have been processed for fast look up */
	TArray<uint8> BoneProcessed;
	BoneProcessed.AddZeroed(NumBones);
#endif
	// Build in 3 passes.
	FTransform* LocalTransformsData = LocalAtoms.GetData(); 
	FTransform* SpaceBasesData = GetEditableSpaceBases().GetData();
	
	GetEditableSpaceBases()[0] = LocalAtoms[0];
#if (UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT)
	BoneProcessed[0] = 1;
#endif

	for(int32 BoneIndex=1; BoneIndex<LocalAtoms.Num(); BoneIndex++)
	{
		FPlatformMisc::Prefetch(SpaceBasesData + BoneIndex);

#if (UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT)
		// Mark bone as processed
		BoneProcessed[BoneIndex] = 1;
#endif
		// For all bones below the root, final component-space transform is relative transform * component-space transform of parent.
		const int32 ParentIndex = SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex);
		FPlatformMisc::Prefetch(SpaceBasesData + ParentIndex);

#if (UE_BUILD_DEBUG || UE_BUILD_DEVELOPMENT)
		// Check the precondition that Parents occur before Children in the RequiredBones array.
		checkSlow(BoneProcessed[ParentIndex] == 1);
#endif
		FTransform::Multiply(SpaceBasesData + BoneIndex, LocalTransformsData + BoneIndex, SpaceBasesData + ParentIndex);

		checkSlow(GetEditableSpaceBases()[BoneIndex].IsRotationNormalized());
		checkSlow(!GetEditableSpaceBases()[BoneIndex].ContainsNaN());
	}
	bNeedToFlipSpaceBaseBuffers = true;
}
Esempio n. 2
0
void UDestructibleComponent::SetChunksWorldTM(const TArray<FUpdateChunksInfo>& UpdateInfos)
{
	const FQuat InvRotation = ComponentToWorld.GetRotation().Inverse();

	for (const FUpdateChunksInfo& UpdateInfo : UpdateInfos)
	{
		// Bone 0 is a dummy root bone
		const int32 BoneIndex = ChunkIdxToBoneIdx(UpdateInfo.ChunkIndex);
		const FVector WorldTranslation	= UpdateInfo.WorldTM.GetLocation();
		const FQuat WorldRotation		= UpdateInfo.WorldTM.GetRotation();

		const FQuat BoneRotation = InvRotation*WorldRotation;
		const FVector BoneTranslation = InvRotation.RotateVector(WorldTranslation - ComponentToWorld.GetTranslation()) / ComponentToWorld.GetScale3D();

		GetEditableSpaceBases()[BoneIndex] = FTransform(BoneRotation, BoneTranslation);
	}

	// Mark the transform as dirty, so the bounds are updated and sent to the render thread
	MarkRenderTransformDirty();

	// New bone positions need to be sent to render thread
	MarkRenderDynamicDataDirty();

	//Update bone visibilty and flip the editable space base buffer
	FlipEditableSpaceBases();
}
Esempio n. 3
0
void UDestructibleComponent::SetChunkWorldRT( int32 ChunkIndex, const FQuat& WorldRotation, const FVector& WorldTranslation )
{
	// Bone 0 is a dummy root bone
	const int32 BoneIndex = ChunkIdxToBoneIdx(ChunkIndex);

	// Mark the transform as dirty, so the bounds are updated and sent to the render thread
	MarkRenderTransformDirty();

	// New bone positions need to be sent to render thread
	MarkRenderDynamicDataDirty();

#if 0
	// Scale is already applied to the ComponentToWorld transform, and is carried into the bones _locally_.
	// So there is no need to set scale in the bone local transforms
	const FTransform WorldRT(WorldRotation, WorldTranslation, ComponentToWorld.GetScale3D());
	SpaceBases(BoneIndex) = WorldRT*ComponentToWorld.Inverse();
#elif 1
	// More optimal form of the above
	const FQuat BoneRotation = ComponentToWorld.GetRotation().Inverse()*WorldRotation;
	const FVector BoneTranslation = ComponentToWorld.GetRotation().Inverse().RotateVector(WorldTranslation - ComponentToWorld.GetTranslation())/ComponentToWorld.GetScale3D();
	GetEditableSpaceBases()[BoneIndex] = FTransform(BoneRotation, BoneTranslation);
#endif
}
Esempio n. 4
0
void USkeletalMeshComponent::PerformBlendPhysicsBones(const TArray<FBoneIndexType>& InRequiredBones, TArray<FTransform>& InLocalAtoms)
{
	// Get drawscale from Owner (if there is one)
	FVector TotalScale3D = ComponentToWorld.GetScale3D();
	FVector RecipScale3D = TotalScale3D.Reciprocal();

	UPhysicsAsset * const PhysicsAsset = GetPhysicsAsset();
	check( PhysicsAsset );

	if (GetNumSpaceBases() == 0)
	{
		return;
	}

	// Get the scene, and do nothing if we can't get one.
	FPhysScene* PhysScene = nullptr;
	if (GetWorld() != nullptr)
	{
		PhysScene = GetWorld()->GetPhysicsScene();
	}

	if (PhysScene == nullptr)
	{
		return;
	}

	// Make sure scratch space is big enough.
	TArray<FAssetWorldBoneTM> WorldBoneTMs;
	WorldBoneTMs.Reset();
	WorldBoneTMs.AddZeroed(GetNumSpaceBases());
	
	FTransform LocalToWorldTM = ComponentToWorld;
	LocalToWorldTM.RemoveScaling();

	TArray<FTransform>& EditableSpaceBases = GetEditableSpaceBases();

	struct FBodyTMPair
	{
		FBodyInstance* BI;
		FTransform TM;
	};

	TArray<FBodyTMPair> PendingBodyTMs;

#if WITH_PHYSX
	// Lock the scenes we need (flags set in InitArticulated)
	if (bHasBodiesInSyncScene)
	{
		SCENE_LOCK_READ(PhysScene->GetPhysXScene(PST_Sync))
	}

	if (bHasBodiesInAsyncScene)
	{
		SCENE_LOCK_READ(PhysScene->GetPhysXScene(PST_Async))
	}
#endif

	// For each bone - see if we need to provide some data for it.
	for(int32 i=0; i<InRequiredBones.Num(); i++)
	{
		int32 BoneIndex = InRequiredBones[i];

		// See if this is a physics bone..
		int32 BodyIndex = PhysicsAsset ? PhysicsAsset->FindBodyIndex(SkeletalMesh->RefSkeleton.GetBoneName(BoneIndex)) : INDEX_NONE;
		// need to update back to physX so that physX knows where it was after blending
		bool bUpdatePhysics = false;
		FBodyInstance* BodyInstance = NULL;

		// If so - get its world space matrix and its parents world space matrix and calc relative atom.
		if(BodyIndex != INDEX_NONE )
		{	
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
			// tracking down TTP 280421. Remove this if this doesn't happen. 
			if ( !ensure(Bodies.IsValidIndex(BodyIndex)) )
			{
				UE_LOG(LogPhysics, Warning, TEXT("%s(Mesh %s, PhysicsAsset %s)"), 
					*GetName(), *GetNameSafe(SkeletalMesh), *GetNameSafe(PhysicsAsset));
				if ( PhysicsAsset )
				{
					UE_LOG(LogPhysics, Warning, TEXT(" - # of BodySetup (%d), # of Bodies (%d), Invalid BodyIndex(%d)"), 
						PhysicsAsset->BodySetup.Num(), Bodies.Num(), BodyIndex);
				}
				continue;
			}
#endif
			BodyInstance = Bodies[BodyIndex];

			//if simulated body copy back and blend with animation
			if(BodyInstance->IsInstanceSimulatingPhysics())
			{
				FTransform PhysTM = BodyInstance->GetUnrealWorldTransform_AssumesLocked();

				// Store this world-space transform in cache.
				WorldBoneTMs[BoneIndex].TM = PhysTM;
				WorldBoneTMs[BoneIndex].bUpToDate = true;

				float UsePhysWeight = (bBlendPhysics)? 1.f : BodyInstance->PhysicsBlendWeight;

				// Find this bones parent matrix.
				FTransform ParentWorldTM;

				// if we wan't 'full weight' we just find 
				if(UsePhysWeight > 0.f)
				{
					if(BoneIndex == 0)
					{
						ParentWorldTM = LocalToWorldTM;
					}
					else
					{
						// If not root, get parent TM from cache (making sure its up-to-date).
						int32 ParentIndex = SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex);
						UpdateWorldBoneTM(WorldBoneTMs, ParentIndex, this, LocalToWorldTM, TotalScale3D);
						ParentWorldTM = WorldBoneTMs[ParentIndex].TM;
					}


					// Then calc rel TM and convert to atom.
					FTransform RelTM = PhysTM.GetRelativeTransform(ParentWorldTM);
					RelTM.RemoveScaling();
					FQuat RelRot(RelTM.GetRotation());
					FVector RelPos =  RecipScale3D * RelTM.GetLocation();
					FTransform PhysAtom = FTransform(RelRot, RelPos, InLocalAtoms[BoneIndex].GetScale3D());

					// Now blend in this atom. See if we are forcing this bone to always be blended in
					InLocalAtoms[BoneIndex].Blend( InLocalAtoms[BoneIndex], PhysAtom, UsePhysWeight );

					if(BoneIndex == 0)
					{
						//We must update RecipScale3D based on the atom scale of the root
						TotalScale3D *= InLocalAtoms[0].GetScale3D();
						RecipScale3D = TotalScale3D.Reciprocal();
					}

					if (UsePhysWeight < 1.f)
					{
						bUpdatePhysics = true;
					}
				}
			}
		}

		// Update SpaceBases entry for this bone now
		if( BoneIndex == 0 )
		{
			EditableSpaceBases[0] = InLocalAtoms[0];
		}
		else
		{
			const int32 ParentIndex	= SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex);
			EditableSpaceBases[BoneIndex] = InLocalAtoms[BoneIndex] * EditableSpaceBases[ParentIndex];

			/**
			* Normalize rotations.
			* We want to remove any loss of precision due to accumulation of error.
			* i.e. A componentSpace transform is the accumulation of all of its local space parents. The further down the chain, the greater the error.
			* SpaceBases are used by external systems, we feed this to PhysX, send this to gameplay through bone and socket queries, etc.
			* So this is a good place to make sure all transforms are normalized.
			*/
			EditableSpaceBases[BoneIndex].NormalizeRotation();
		}

		if (bUpdatePhysics && BodyInstance)
		{
			//This is extremely inefficient. We need to obtain a write lock which will block other threads from blending
			//For now I'm juts deferring it to the end of this loop, but in general we need to move it all out of here and do it when the blend task is done
			FBodyTMPair* BodyTMPair = new (PendingBodyTMs) FBodyTMPair;
			BodyTMPair->BI = BodyInstance;
			BodyTMPair->TM = EditableSpaceBases[BoneIndex] * ComponentToWorld;
		}
	}

#if WITH_PHYSX
	//See above for read lock instead of write lock
	// Unlock the scenes 
	if (bHasBodiesInSyncScene)
	{
		SCENE_UNLOCK_READ(PhysScene->GetPhysXScene(PST_Sync))
	}

	if (bHasBodiesInAsyncScene)
	{
		SCENE_UNLOCK_READ(PhysScene->GetPhysXScene(PST_Async))
	}

	if(PendingBodyTMs.Num())
	{
		//This is extremely inefficient. We need to obtain a write lock which will block other threads from blending
		//For now I'm juts deferring it to the end of this loop, but in general we need to move it all out of here and do it when the blend task is done

		if (bHasBodiesInSyncScene)
		{
			SCENE_LOCK_WRITE(PhysScene->GetPhysXScene(PST_Sync))
		}

		if (bHasBodiesInAsyncScene)
		{
			SCENE_LOCK_WRITE(PhysScene->GetPhysXScene(PST_Async))
		}

		for (const FBodyTMPair& BodyTMPair : PendingBodyTMs)
		{
			BodyTMPair.BI->SetBodyTransform(BodyTMPair.TM, ETeleportType::TeleportPhysics);
		}

		if (bHasBodiesInSyncScene)
		{
			SCENE_UNLOCK_WRITE(PhysScene->GetPhysXScene(PST_Sync))
		}

		if (bHasBodiesInAsyncScene)
		{
			SCENE_UNLOCK_WRITE(PhysScene->GetPhysXScene(PST_Async))
		}
    }
#endif
	

	// Transforms updated, cached local bounds are now out of date.
	InvalidateCachedBounds();
}