void UAnimGraphNode_BoneDrivenController::Draw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* SkelMeshComp) const
{	
	static const float ArrowHeadWidth = 5.0f;
	static const float ArrowHeadHeight = 8.0f;

	const int32 SourceIdx = SkelMeshComp->GetBoneIndex(Node.SourceBone.BoneName);
	const int32 TargetIdx = SkelMeshComp->GetBoneIndex(Node.TargetBone.BoneName);

	if ((SourceIdx != INDEX_NONE) && (TargetIdx != INDEX_NONE))
	{
		const FTransform SourceTM = SkelMeshComp->GetSpaceBases()[SourceIdx] * SkelMeshComp->ComponentToWorld;
		const FTransform TargetTM = SkelMeshComp->GetSpaceBases()[TargetIdx] * SkelMeshComp->ComponentToWorld;

		PDI->DrawLine(TargetTM.GetLocation(), SourceTM.GetLocation(), FLinearColor(0.0f, 0.0f, 1.0f), SDPG_Foreground, 0.5f);

		const FVector ToTarget = TargetTM.GetTranslation() - SourceTM.GetTranslation();
		const FVector UnitToTarget = ToTarget.GetSafeNormal();
		FVector Midpoint = SourceTM.GetTranslation() + 0.5f * ToTarget + 0.5f * UnitToTarget * ArrowHeadHeight;

		FVector YAxis;
		FVector ZAxis;
		UnitToTarget.FindBestAxisVectors(YAxis, ZAxis);
		const FMatrix ArrowMatrix(UnitToTarget, YAxis, ZAxis, Midpoint);

		DrawConnectedArrow(PDI, ArrowMatrix, FLinearColor(0.0f, 1.0f, 0.0), ArrowHeadHeight, ArrowHeadWidth, SDPG_Foreground);

		PDI->DrawPoint(SourceTM.GetTranslation(), FLinearColor(0.8f, 0.8f, 0.2f), 5.0f, SDPG_Foreground);
		PDI->DrawPoint(SourceTM.GetTranslation() + ToTarget, FLinearColor(0.8f, 0.8f, 0.2f), 5.0f, SDPG_Foreground);
	}
}
Example #2
0
void FConstraintInstance::SetRefFrame(EConstraintFrame::Type Frame, const FTransform& RefFrame)
{
#if WITH_PHYSX
	PxJointActorIndex::Enum PxFrame = U2PConstraintFrame(Frame);
#endif
	if(Frame == EConstraintFrame::Frame1)
	{
		Pos1 = RefFrame.GetTranslation();
		PriAxis1 = RefFrame.GetUnitAxis( EAxis::X );
		SecAxis1 = RefFrame.GetUnitAxis( EAxis::Y );
	}
	else
	{
		Pos2 = RefFrame.GetTranslation();
		PriAxis2 = RefFrame.GetUnitAxis( EAxis::X );
		SecAxis2 = RefFrame.GetUnitAxis( EAxis::Y );
	}

#if WITH_PHYSX
	if (PxD6Joint* Joint = GetUnbrokenJoint())
	{
		PxTransform PxRefFrame = U2PTransform(RefFrame);
		Joint->setLocalPose(PxFrame, PxRefFrame);
	}
#endif

}
void FAnimNode_HandIKRetargeting::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer& RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
	checkSlow(OutBoneTransforms.Num() == 0);

	// Get component space transforms for all of our IK and FK bones.
	FTransform const RightHandFKTM = MeshBases.GetComponentSpaceTransform(RightHandFK.BoneIndex);
	FTransform const LeftHandFKTM = MeshBases.GetComponentSpaceTransform(LeftHandFK.BoneIndex);
	FTransform const RightHandIKTM = MeshBases.GetComponentSpaceTransform(RightHandIK.BoneIndex);
	FTransform const LeftHandIKTM = MeshBases.GetComponentSpaceTransform(LeftHandIK.BoneIndex);
	
	// Compute weight FK and IK hand location. And translation from IK to FK.
	FVector const FKLocation = FMath::Lerp<FVector>(LeftHandFKTM.GetTranslation(), RightHandFKTM.GetTranslation(), HandFKWeight);
	FVector const IKLocation = FMath::Lerp<FVector>(LeftHandIKTM.GetTranslation(), RightHandIKTM.GetTranslation(), HandFKWeight);
	FVector const IK_To_FK_Translation = FKLocation - IKLocation;

	// If we're not translating, don't send any bones to update.
	if (!IK_To_FK_Translation.IsNearlyZero())
	{
		// Move desired bones
		for (int32 BoneIndex = 0; BoneIndex < IKBonesToMove.Num(); BoneIndex++)
		{
			FBoneReference const & BoneReference = IKBonesToMove[BoneIndex];
			if (BoneReference.IsValid(RequiredBones))
			{
				FTransform BoneTransform = MeshBases.GetComponentSpaceTransform(BoneReference.BoneIndex);
				BoneTransform.AddToTranslation(IK_To_FK_Translation);

				OutBoneTransforms.Add(FBoneTransform(BoneReference.BoneIndex, BoneTransform));
			}
		}
	}
}
void UDebugSkelMeshComponent::ConsumeRootMotion(const FVector& FloorMin, const FVector& FloorMax)
{
	if (bPreviewRootMotion)
	{
		if (UAnimInstance* AnimInst = GetAnimInstance())
		{
			FRootMotionMovementParams ExtractedRootMotion = AnimInst->ConsumeExtractedRootMotion();
			if (ExtractedRootMotion.bHasRootMotion)
			{
				AddLocalTransform(ExtractedRootMotion.RootMotionTransform);

				//Handle moving component so that it stays within the editor floor
				FTransform CurrentTransform = GetRelativeTransform();
				FVector Trans = CurrentTransform.GetTranslation();
				Trans.X = WrapInRange(Trans.X, FloorMin.X, FloorMax.X);
				Trans.Y = WrapInRange(Trans.Y, FloorMin.Y, FloorMax.Y);
				CurrentTransform.SetTranslation(Trans);
				SetRelativeTransform(CurrentTransform);
			}
		}
	}
	else
	{
		SetWorldTransform(FTransform());
	}
}
void FAnimNode_CopyBone::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer & RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
	check(OutBoneTransforms.Num() == 0);

	// Pass through if we're not doing anything.
	if( !bCopyTranslation && !bCopyRotation && !bCopyScale )
	{
		return;
	}

	// Get component space transform for source and current bone.
	FTransform SourceBoneTM = MeshBases.GetComponentSpaceTransform(SourceBone.BoneIndex);
	FTransform CurrentBoneTM = MeshBases.GetComponentSpaceTransform(TargetBone.BoneIndex);

	// Copy individual components
	if (bCopyTranslation)
	{
		CurrentBoneTM.SetTranslation( SourceBoneTM.GetTranslation() );
	}

	if (bCopyRotation)
	{
		CurrentBoneTM.SetRotation( SourceBoneTM.GetRotation() );
	}

	if (bCopyScale)
	{
		CurrentBoneTM.SetScale3D( SourceBoneTM.GetScale3D() );
	}

	// Output new transform for current bone.
	OutBoneTransforms.Add( FBoneTransform(TargetBone.BoneIndex, CurrentBoneTM) );
}
void AProjectTapGameMode::StartPlay()
{
    Super::StartPlay();
    auto gameState = GetGameState<AProjectTapGameState>();
    ABallPawn* ball = nullptr;
    if ( UWorld* world = GetWorld() )
    {
        AActor* playerStart = FindPlayerStart( 0 , FString( "Player" ) );
        FTransform playerTransform = playerStart->GetTransform();
        if ( ABallPlayerStart* realPlayerStart = Cast<ABallPlayerStart>( playerStart ) )
        {
            auto possibleCamera = realPlayerStart->camera == nullptr ? nullptr : Cast<UProjectTapCameraComponent>( realPlayerStart->camera->GetComponentByClass( UProjectTapCameraComponent::StaticClass() ) );
            FActorSpawnParameters params;
            ball = world->SpawnActor<ABallPawn>(
                       ABallPawn::StaticClass() ,
                       playerTransform.GetTranslation() ,
                       FRotator( playerTransform.GetRotation() ) ,
                       params );

            if ( ball != nullptr )
            {
                ball->AddVelocity( realPlayerStart->initialVelocity , realPlayerStart->GetActorLocation() );
                if ( possibleCamera != nullptr && realPlayerStart->followPlayer )
                {
                    ball->setCamera( realPlayerStart );
                    possibleCamera = ball->GetCamera();
                }
            }
            gameState->SetCamera( possibleCamera );
            isMenu = realPlayerStart->GameMode == CustomGameMode::GAME_MODE_MAIN_MENU;
            if ( realPlayerStart->music != nullptr )musicPlayer->SetSound( realPlayerStart->music );
        }
        else
        {
            FActorSpawnParameters params;
            ball = world->SpawnActor<ABallPawn>( ABallPawn::StaticClass() , playerTransform.GetTranslation() , FRotator( playerTransform.GetRotation() ) , params );
        }

        gameState->SetPlayer(ball);
    }
    musicPlayer->Play();
    musicPlayer->SetVolumeMultiplier( 0 );

    gameState->SetGameState( CustomGameState::GAME_STATE_PLAYING );
    if ( isMenu ) gameState->SetGameMode( CustomGameMode::GAME_MODE_MAIN_MENU );
}
FQuat FAnimNode_RotationMultiplier::ExtractAngle(const FTransform& RefPoseTransform, const FTransform& LocalBoneTransform, const EBoneAxis Axis)
{
	// local bone transform with reference rotation
	FTransform ReferenceBoneTransform = RefPoseTransform;
	ReferenceBoneTransform.SetTranslation(LocalBoneTransform.GetTranslation());

	// find delta angle between the two quaternions X Axis.
	const FVector RotationAxis = GetAxisVector(Axis);
	const FVector LocalRotationVector = LocalBoneTransform.GetRotation().RotateVector(RotationAxis);
	const FVector ReferenceRotationVector = ReferenceBoneTransform.GetRotation().RotateVector(RotationAxis);

	const FQuat LocalToRefQuat = FQuat::FindBetween(LocalRotationVector, ReferenceRotationVector);
	checkSlow( LocalToRefQuat.IsNormalized() );

	// Rotate parent bone atom from position in local space to reference skeleton
	// Since our rotation rotates both vectors with shortest arc
	// we're essentially left with a quaternion that has angle difference with reference skeleton version
	const FQuat BoneQuatAligned = LocalToRefQuat* LocalBoneTransform.GetRotation();
	checkSlow( BoneQuatAligned.IsNormalized() );

	// Find that delta angle
	const FQuat DeltaQuat = (ReferenceBoneTransform.GetRotation().Inverse()) * BoneQuatAligned;
	checkSlow( DeltaQuat.IsNormalized() );

#if 0 //DEBUG_TWISTBONECONTROLLER
	UE_LOG(LogSkeletalControl, Log, TEXT("\t ExtractAngle, Bone: %s"), 
		*SourceBone.BoneName.ToString());
	UE_LOG(LogSkeletalControl, Log, TEXT("\t\t Bone Quat: %s, Rot: %s, AxisX: %s"), *LocalBoneTransform.GetRotation().ToString(), *LocalBoneTransform.GetRotation().Rotator().ToString(), *LocalRotationVector.ToString() );
	UE_LOG(LogSkeletalControl, Log, TEXT("\t\t BoneRef Quat: %s, Rot: %s, AxisX: %s"), *ReferenceBoneTransform.GetRotation().ToString(), *ReferenceBoneTransform.GetRotation().Rotator().ToString(), *ReferenceRotationVector.ToString() );
	UE_LOG(LogSkeletalControl, Log, TEXT("\t\t LocalToRefQuat Quat: %s, Rot: %s"), *LocalToRefQuat.ToString(), *LocalToRefQuat.Rotator().ToString() );

	const FVector BoneQuatAlignedX = LocalBoneTransform.GetRotation().RotateVector(RotationAxis);
	UE_LOG(LogSkeletalControl, Log, TEXT("\t\t BoneQuatAligned Quat: %s, Rot: %s, AxisX: %s"), *BoneQuatAligned.ToString(), *BoneQuatAligned.Rotator().ToString(), *BoneQuatAlignedX.ToString() );
	UE_LOG(LogSkeletalControl, Log, TEXT("\t\t DeltaQuat Quat: %s, Rot: %s"), *DeltaQuat.ToString(), *DeltaQuat.Rotator().ToString() );

	FTransform BoneAtomAligned(BoneQuatAligned, ReferenceBoneTransform.GetTranslation());
	const FQuat DeltaQuatAligned = FQuat::FindBetween(BoneAtomAligned.GetScaledAxis( EAxis::X ), ReferenceBoneTransform.GetScaledAxis( EAxis::X ));
	UE_LOG(LogSkeletalControl, Log, TEXT("\t\t DeltaQuatAligned Quat: %s, Rot: %s"), *DeltaQuatAligned.ToString(), *DeltaQuatAligned.Rotator().ToString() );
	FVector DeltaAxis;
	float	DeltaAngle;
	DeltaQuat.ToAxisAndAngle(DeltaAxis, DeltaAngle);
	UE_LOG(LogSkeletalControl, Log, TEXT("\t\t DeltaAxis: %s, DeltaAngle: %f"), *DeltaAxis.ToString(), DeltaAngle );
#endif

	return DeltaQuat;
}
FTransform USkeletalMeshComponent::ConvertLocalRootMotionToWorld(const FTransform & InTransform)
{
	// Make sure component to world is up to date
	if (!bWorldToComponentUpdated)
	{
		UpdateComponentToWorld();
	}

	const FTransform NewWorldTransform = InTransform * ComponentToWorld;
	const FVector DeltaWorldTranslation = NewWorldTransform.GetTranslation() - ComponentToWorld.GetTranslation();
	const FQuat DeltaWorldRotation = ComponentToWorld.GetRotation().Inverse() * NewWorldTransform.GetRotation();

	const FTransform DeltaWorldTransform(DeltaWorldRotation, DeltaWorldTranslation);

	UE_LOG(LogRootMotion, Log,  TEXT("ConvertLocalRootMotionToWorld LocalT: %s, LocalR: %s, WorldT: %s, WorldR: %s."),
		*InTransform.GetTranslation().ToCompactString(), *InTransform.GetRotation().Rotator().ToCompactString(), 
		*DeltaWorldTransform.GetTranslation().ToCompactString(), *DeltaWorldTransform.GetRotation().Rotator().ToCompactString() );

	return DeltaWorldTransform;
}
FBox FKSphereElem::CalcAABB(const FTransform& BoneTM, float Scale) const
{
	FTransform ElemTM = GetTransform();
	ElemTM.ScaleTranslation( FVector(Scale) );
	ElemTM *= BoneTM;

	const FVector BoxCenter = ElemTM.GetTranslation();
	const FVector BoxExtents(Radius * Scale);

	return FBox(BoxCenter - BoxExtents, BoxCenter + BoxExtents);
}
void AActor::EditorApplyTranslation(const FVector& DeltaTranslation, bool bAltDown, bool bShiftDown, bool bCtrlDown)
{
	if( RootComponent != NULL )
	{
		FTransform NewTransform = GetRootComponent()->GetComponentTransform();
		NewTransform.SetTranslation(NewTransform.GetTranslation() + DeltaTranslation);
		GetRootComponent()->SetWorldTransform(NewTransform);
	}
	else
	{
		UE_LOG(LogActor, Warning, TEXT("WARNING: EditorApplyTranslation %s has no root component"), *GetName() );
	}
}
float FAttenuationSettings::AttenuationEvalCapsule(const FTransform& SoundTransform, const FVector ListenerLocation, const float DistanceScale) const
{
    float Distance = 0.f;
    const float CapsuleHalfHeight = AttenuationShapeExtents.X;
    const float CapsuleRadius = AttenuationShapeExtents.Y;

    // Capsule devolves to a sphere if HalfHeight <= Radius
    if (CapsuleHalfHeight <= CapsuleRadius )
    {
        Distance = FMath::Max(FVector::Dist( SoundTransform.GetTranslation(), ListenerLocation ) - CapsuleRadius, 0.f);
    }
    else
    {
        const FVector PointOffset = (CapsuleHalfHeight - CapsuleRadius) * SoundTransform.GetUnitAxis( EAxis::Z );
        const FVector StartPoint = SoundTransform.GetTranslation() + PointOffset;
        const FVector EndPoint = SoundTransform.GetTranslation() - PointOffset;

        Distance = FMath::PointDistToSegment(ListenerLocation, StartPoint, EndPoint) - CapsuleRadius;
    }

    return AttenuationEval(Distance, FalloffDistance, DistanceScale);
}
Example #12
0
void FTransformCurve::UpdateOrAddKey(const FTransform& NewKey, float CurrentTime)
{
	TranslationCurve.UpdateOrAddKey(NewKey.GetTranslation(), CurrentTime);
	// pitch, yaw, roll order - please check Evaluate function
	FVector RotationAsVector;
	FRotator Rotator = NewKey.GetRotation().Rotator();
	RotationAsVector.X = Rotator.Roll;
	RotationAsVector.Y = Rotator.Pitch;
	RotationAsVector.Z = Rotator.Yaw;

	RotationCurve.UpdateOrAddKey(RotationAsVector, CurrentTime);
	ScaleCurve.UpdateOrAddKey(NewKey.GetScale3D(), CurrentTime);
}
void FAnimNode_CopyBone::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, FCSPose<FCompactPose>& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
	check(OutBoneTransforms.Num() == 0);

	// Pass through if we're not doing anything.
	if( !bCopyTranslation && !bCopyRotation && !bCopyScale )
	{
		return;
	}

	// Get component space transform for source and current bone.
	const FBoneContainer& BoneContainer = MeshBases.GetPose().GetBoneContainer();
	FCompactPoseBoneIndex SourceBoneIndex = SourceBone.GetCompactPoseIndex(BoneContainer);
	FCompactPoseBoneIndex TargetBoneIndex = TargetBone.GetCompactPoseIndex(BoneContainer);

	FTransform SourceBoneTM = MeshBases.GetComponentSpaceTransform(SourceBoneIndex);
	FTransform CurrentBoneTM = MeshBases.GetComponentSpaceTransform(TargetBoneIndex);

	if(ControlSpace != BCS_ComponentSpace)
	{
		// Convert out to selected space
		FAnimationRuntime::ConvertCSTransformToBoneSpace(SkelComp, MeshBases, SourceBoneTM, SourceBoneIndex, ControlSpace);
		FAnimationRuntime::ConvertCSTransformToBoneSpace(SkelComp, MeshBases, CurrentBoneTM, TargetBoneIndex, ControlSpace);
	}
	
	// Copy individual components
	if (bCopyTranslation)
	{
		CurrentBoneTM.SetTranslation( SourceBoneTM.GetTranslation() );
	}

	if (bCopyRotation)
	{
		CurrentBoneTM.SetRotation( SourceBoneTM.GetRotation() );
	}

	if (bCopyScale)
	{
		CurrentBoneTM.SetScale3D( SourceBoneTM.GetScale3D() );
	}

	if(ControlSpace != BCS_ComponentSpace)
	{
		// Convert back out if we aren't operating in component space
		FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, CurrentBoneTM, TargetBoneIndex, ControlSpace);
	}

	// Output new transform for current bone.
	OutBoneTransforms.Add(FBoneTransform(TargetBoneIndex, CurrentBoneTM));
}
void UPhysicsHandleComponent::UpdateHandleTransform(const FTransform& NewTransform)
{
	if(!KinActorData)
	{
		return;
	}

#if WITH_PHYSX
	bool bChangedPosition = true;
	bool bChangedRotation = true;

	PxRigidDynamic* KinActor = KinActorData;

	// Check if the new location is worthy of change
	PxVec3 PNewLocation = U2PVector(NewTransform.GetTranslation());
	PxVec3 PCurrentLocation = KinActor->getGlobalPose().p;
	if((PNewLocation - PCurrentLocation).magnitudeSquared() <= 0.01f*0.01f)
	{
		PNewLocation = PCurrentLocation;
		bChangedPosition = false;
	}

	// Check if the new rotation is worthy of change
	PxQuat PNewOrientation = U2PQuat(NewTransform.GetRotation());
	PxQuat PCurrentOrientation = KinActor->getGlobalPose().q;
	if(!(FMath::Abs(PNewOrientation.dot(PCurrentOrientation)) < (1.f - KINDA_SMALL_NUMBER)))
	{
		PNewOrientation = PCurrentOrientation;
		bChangedRotation = false;
	}

	// Don't call moveKinematic if it hasn't changed - that will stop bodies from going to sleep.
	if (bChangedPosition || bChangedRotation)
	{
		KinActor->setKinematicTarget(PxTransform(PNewLocation, PNewOrientation));

		//LOC_MOD
		//PxD6Joint* Joint = (PxD6Joint*) HandleData;
		//if(Joint)// && (PNewLocation - PCurrentLocation).magnitudeSquared() > 0.01f*0.01f)
		//{
		//	PxRigidActor* Actor0, *Actor1;
		//	Joint->getActors(Actor0, Actor1);
		//	//Joint->setDrivePosition(PxTransform(Actor0->getGlobalPose().transformInv(PNewLocation)));
		//	Joint->setDrivePosition(PxTransform::createIdentity());
		//	//Joint->setDriveVelocity(PxVec3(0), PxVec3(0));
		//}
	}
#endif // WITH_PHYSX
}
//=============================================================================
static void TransformToSteamSpace(const FTransform& In, vr::HmdMatrix34_t& Out, float WorldToMeterScale)
{
	const FRotator InRot = In.Rotator();
	FRotator OutRot(InRot.Yaw, -InRot.Roll, -InRot.Pitch);

	const FVector InPos = In.GetTranslation();
	FVector OutPos(InPos.Y, InPos.Z, -InPos.X);
	OutPos /= WorldToMeterScale;

	const FVector InScale = In.GetScale3D();
	FVector OutScale(InScale.Y, InScale.Z, -InScale.X);
	OutScale /= WorldToMeterScale;

	Out = FSteamVRHMD::ToHmdMatrix34(FTransform(OutRot, OutPos, OutScale).ToMatrixNoScale());
}
bool UPrimitiveComponent::GetRigidBodyState(FRigidBodyState& OutState, FName BoneName)
{
	FBodyInstance* BI = GetBodyInstance(BoneName);
	if (BI && BI->IsInstanceSimulatingPhysics())
	{
		FTransform BodyTM = BI->GetUnrealWorldTransform();
		OutState.Position = BodyTM.GetTranslation();
		OutState.Quaternion = BodyTM.GetRotation();
		OutState.LinVel = BI->GetUnrealWorldVelocity();
		OutState.AngVel = BI->GetUnrealWorldAngularVelocity();
		OutState.Flags = (BI->IsInstanceAwake() ? ERigidBodyFlags::None : ERigidBodyFlags::Sleeping);
		return true;
	}

	return false;
}
void UAURSmoothingFilterKalman::Measurement(FTransform const & MeasuredTransform)
{
	try
	{
		FVector translation = MeasuredTransform.GetTranslation();

		FString msg = "In: " + translation.ToString();
		//FQuat rotation = MeasuredTransform.GetRotation();

		TransformAsMat.at<float>(0) = translation.X;
		TransformAsMat.at<float>(1) = translation.Y;
		TransformAsMat.at<float>(2) = translation.Z;
		//TransformAsMat.at<float>(3) = rotation.X * rotation.W;
		//TransformAsMat.at<float>(4) = rotation.Y * rotation.W;
		//TransformAsMat.at<float>(5) = rotation.Z * rotation.W;

		cv::Mat FilterResult = Filter.predict();
		Filter.correct(TransformAsMat);

		translation.Set(FilterResult.at<float>(0), FilterResult.at<float>(1), FilterResult.at<float>(2));

		msg += "\nOut: " + translation.ToString();

		UE_LOG(LogAUR, Log, TEXT("%s"), *msg);

		//FVector rot_axis(FilterResult.at<float>(3), FilterResult.at<float>(4), FilterResult.at<float>(5));
		//float rot_magnitude = rot_axis.Size();
		//rot_axis.Normalize();

		//rotation.X = rot_axis.X;
		//rotation.Y = rot_axis.Y;
		//rotation.Z = rot_axis.Z;
		//rotation.W = rot_magnitude;
	
		CurrentTransform.SetComponents(MeasuredTransform.GetRotation(), translation, FVector(1, 1, 1));
	}
	catch (cv::Exception& e)
	{
		FString exception_msg(e.what());

		UE_LOG(LogAUR, Error, TEXT("Kalman: %s"), *exception_msg)

		CurrentTransform = MeasuredTransform;
	}
}
void UGripMotionControllerComponent::UpdatePhysicsHandleTransform(const FBPActorGripInformation &GrippedActor, const FTransform& NewTransform)
{
	if (!GrippedActor.Actor && !GrippedActor.Component)
		return;

	FBPActorPhysicsHandleInformation * HandleInfo = GetPhysicsGrip(GrippedActor);

	if (!HandleInfo || !HandleInfo->KinActorData)
		return;

#if WITH_PHYSX
	bool bChangedPosition = true;
	bool bChangedRotation = true;

	PxRigidDynamic* KinActor = HandleInfo->KinActorData;
	PxScene* PScene = GetPhysXSceneFromIndex(HandleInfo->SceneIndex);
	SCOPED_SCENE_WRITE_LOCK(PScene);

	// Check if the new location is worthy of change
	PxVec3 PNewLocation = U2PVector(NewTransform.GetTranslation());
	PxVec3 PCurrentLocation = KinActor->getGlobalPose().p;
	if ((PNewLocation - PCurrentLocation).magnitudeSquared() <= 0.01f*0.01f)
	{
		PNewLocation = PCurrentLocation;
		bChangedPosition = false;
	}

	// Check if the new rotation is worthy of change
	PxQuat PNewOrientation = U2PQuat(NewTransform.GetRotation());
	PxQuat PCurrentOrientation = KinActor->getGlobalPose().q;
	if ((FMath::Abs(PNewOrientation.dot(PCurrentOrientation)) > (1.f - SMALL_NUMBER)))
	{
		PNewOrientation = PCurrentOrientation;
		bChangedRotation = false;
	}

	// Don't call moveKinematic if it hasn't changed - that will stop bodies from going to sleep.
	if (bChangedPosition || bChangedRotation)
	{
		KinActor->setKinematicTarget(PxTransform(PNewLocation, PNewOrientation));
	}
#endif // WITH_PHYSX
}
float FAttenuationSettings::AttenuationEvalCone(const FTransform& SoundTransform, const FVector ListenerLocation, const float DistanceScale) const
{
    const FVector SoundForward = SoundTransform.GetUnitAxis( EAxis::X );

    float VolumeMultiplier = 1.f;

    const FVector Origin = SoundTransform.GetTranslation() - (SoundForward * ConeOffset);

    const float Distance = FMath::Max(FVector::Dist( Origin, ListenerLocation ) - AttenuationShapeExtents.X, 0.f);
    VolumeMultiplier *= AttenuationEval(Distance, FalloffDistance, DistanceScale);

    if (VolumeMultiplier > 0.f)
    {
        const float theta = FMath::RadiansToDegrees(fabsf(FMath::Acos( FVector::DotProduct(SoundForward, (ListenerLocation - Origin).GetSafeNormal()))));
        VolumeMultiplier *= AttenuationEval(theta - AttenuationShapeExtents.Y, AttenuationShapeExtents.Z, 1.0f);
    }

    return VolumeMultiplier;
}
void UDebugSkelMeshComponent::ConsumeRootMotion(const FVector& FloorMin, const FVector& FloorMax)
{
	//Extract root motion regardless of where we use it so that we don't hit
	//problems with it building up in the instance

	FRootMotionMovementParams ExtractedRootMotion;

	if (UAnimInstance* AnimInst = GetAnimInstance())
	{
		ExtractedRootMotion = AnimInst->ConsumeExtractedRootMotion(1.f);
	}

	if (bPreviewRootMotion)
	{
		if (ExtractedRootMotion.bHasRootMotion)
		{
			AddLocalTransform(ExtractedRootMotion.RootMotionTransform);

			//Handle moving component so that it stays within the editor floor
			FTransform CurrentTransform = GetRelativeTransform();
			FVector Trans = CurrentTransform.GetTranslation();
			Trans.X = WrapInRange(Trans.X, FloorMin.X, FloorMax.X);
			Trans.Y = WrapInRange(Trans.Y, FloorMin.Y, FloorMax.Y);
			CurrentTransform.SetTranslation(Trans);
			SetRelativeTransform(CurrentTransform);
		}
	}
	else
	{
		if (TurnTableMode == EPersonaTurnTableMode::Stopped)
		{
			SetWorldTransform(FTransform());
		}
		else
		{
			SetRelativeLocation(FVector::ZeroVector);
		}
	}
}
Example #21
0
void UAnimCompositeBase::ExtractRootMotionFromTrack(const FAnimTrack &SlotAnimTrack, float StartTrackPosition, float EndTrackPosition, FRootMotionMovementParams &RootMotion) const
{
	TArray<FRootMotionExtractionStep> RootMotionExtractionSteps;
	SlotAnimTrack.GetRootMotionExtractionStepsForTrackRange(RootMotionExtractionSteps, StartTrackPosition, EndTrackPosition);

	UE_LOG(LogRootMotion, Log, TEXT("\tUAnimMontage::ExtractRootMotionForTrackRange, NumSteps: %d, StartTrackPosition: %.3f, EndTrackPosition: %.3f"),
		RootMotionExtractionSteps.Num(), StartTrackPosition, EndTrackPosition);

	// Go through steps sequentially, extract root motion, and accumulate it.
	// This has to be done in order so root motion translation & rotation is applied properly (as translation is relative to rotation)
	for (int32 StepIndex = 0; StepIndex < RootMotionExtractionSteps.Num(); StepIndex++)
	{
		const FRootMotionExtractionStep & CurrentStep = RootMotionExtractionSteps[StepIndex];
		if (CurrentStep.AnimSequence->bEnableRootMotion)
		{
			FTransform DeltaTransform = CurrentStep.AnimSequence->ExtractRootMotionFromRange(CurrentStep.StartPosition, CurrentStep.EndPosition);
			RootMotion.Accumulate(DeltaTransform);
		
			UE_LOG(LogRootMotion, Log, TEXT("\t\tCurrentStep: %d, StartPos: %.3f, EndPos: %.3f, Anim: %s DeltaTransform Translation: %s, Rotation: %s"),
				StepIndex, CurrentStep.StartPosition, CurrentStep.EndPosition, *CurrentStep.AnimSequence->GetName(),
				*DeltaTransform.GetTranslation().ToCompactString(), *DeltaTransform.GetRotation().Rotator().ToCompactString());
		}
	}
}
FCreatureBoneData 
ACreatureActor::GetBluePrintBoneData(FString name_in, bool world_transform)
{

	FCreatureBoneData ret_data;
	for (size_t i = 0; i < bone_data.Num(); i++)
	{
		if (bone_data[i].name == name_in)
		{
			ret_data = bone_data[i];
			if (world_transform)
			{
				FTransform xform = GetTransform();
				FVector world_location = xform.GetTranslation();
				ret_data.point1 = xform.TransformPosition(ret_data.point1);
				ret_data.point2 = xform.TransformPosition(ret_data.point2);
			}

			break;
		}
	}

	return ret_data;
}
void UGripMotionControllerComponent::TickGrip()
{
	if (GrippedActors.Num())
	{
		FTransform WorldTransform;
		FTransform InverseTransform = this->GetComponentTransform().Inverse();

		for (int i = GrippedActors.Num() - 1; i >= 0; --i)
		{
			if (GrippedActors[i].Actor || GrippedActors[i].Component)
			{
				// GetRelativeTransformReverse had some serious fucking floating point errors associated with it that was fucking everything up
				// Not sure whats wrong with the function but I might want to push a patch out eventually
				WorldTransform = GrippedActors[i].RelativeTransform.GetRelativeTransform(InverseTransform);

				UPrimitiveComponent *root = GrippedActors[i].Component;
				AActor *actor = GrippedActors[i].Actor;

				if (!root)
					root = Cast<UPrimitiveComponent>(GrippedActors[i].Actor->GetRootComponent());

				if (!root)
					continue;

				if (!actor)
					actor = root->GetOwner();

				if (!actor)
					continue;

				if (bIsServer)
				{
					// Handle collision intersection detection, this is used to intelligently manage some of the networking and late update features.
					switch (GrippedActors[i].GripCollisionType.GetValue())
					{
					case EGripCollisionType::InteractiveCollisionWithPhysics:
					case EGripCollisionType::InteractiveHybridCollisionWithSweep:
					{
						TArray<FOverlapResult> Hits;
						FComponentQueryParams Params(NAME_None, this->GetOwner());
						Params.bTraceAsyncScene = root->bCheckAsyncSceneOnMove;
						Params.AddIgnoredActor(actor);
						Params.AddIgnoredActors(root->MoveIgnoreActors);

						if(GetWorld()->ComponentOverlapMulti(Hits, root, root->GetComponentLocation(), root->GetComponentQuat(), Params))
						{
							GrippedActors[i].bColliding = true;
						}
						else
						{
							GrippedActors[i].bColliding = false;
						}
					}

					// Skip collision intersects with these types, they dont need it
					case EGripCollisionType::PhysicsOnly:
					case EGripCollisionType::SweepWithPhysics:
					case EGripCollisionType::InteractiveCollisionWithSweep:
					default:break;
					}
				}

				// Need to figure out best default behavior
				/*if (GrippedActors[i].bHasSecondaryAttachment && GrippedActors[i].SecondaryAttachment)
				{
				WorldTransform.SetRotation((WorldTransform.GetLocation() - GrippedActors[i].SecondaryAttachment->GetComponentLocation()).ToOrientationRotator().Quaternion());
				}*/

				if (GrippedActors[i].GripCollisionType == EGripCollisionType::InteractiveCollisionWithPhysics)
				{
					UpdatePhysicsHandleTransform(GrippedActors[i], WorldTransform);
				}
				else if (GrippedActors[i].GripCollisionType == EGripCollisionType::InteractiveCollisionWithSweep)
				{
					if (bIsServer)
					{
						FHitResult OutHit;

						// Need to use without teleport so that the physics velocity is updated for when the actor is released to throw
						root->SetWorldTransform(WorldTransform, true, &OutHit);

						if (OutHit.bBlockingHit)
						{
							GrippedActors[i].bColliding = true;

							if (!actor->bReplicateMovement)
								actor->SetReplicateMovement(true);
						}
						else
						{
							GrippedActors[i].bColliding = false;

							if (actor->bReplicateMovement)
								actor->SetReplicateMovement(false);
						}
					}
					else
					{
						if (!GrippedActors[i].bColliding)
						{
							root->SetWorldTransform(WorldTransform, true);
						}
					}
				}
				else if (GrippedActors[i].GripCollisionType == EGripCollisionType::InteractiveHybridCollisionWithSweep)
				{
					// Need to use without teleport so that the physics velocity is updated for when the actor is released to throw
					//if (bIsServer)
					//{
					FBPActorPhysicsHandleInformation * GripHandle = GetPhysicsGrip(GrippedActors[i]);
					if (!GrippedActors[i].bColliding)
					{
						// Make sure that there is no collision on course before turning off collision and snapping to controller
						if (bIsServer && actor && actor->bReplicateMovement)
						{
							FCollisionQueryParams QueryParams(NAME_None, false, this->GetOwner());
							FCollisionResponseParams ResponseParam;
							root->InitSweepCollisionParams(QueryParams, ResponseParam);
							QueryParams.AddIgnoredActor(actor);
							QueryParams.AddIgnoredActors(root->MoveIgnoreActors);

							if (GetWorld()->SweepTestByChannel(root->GetComponentLocation(), WorldTransform.GetLocation(), root->GetComponentQuat(), ECollisionChannel::ECC_Visibility, root->GetCollisionShape(), QueryParams, ResponseParam))
							{
								GrippedActors[i].bColliding = true;
							}
							else
							{
								GrippedActors[i].bColliding = false;
							}
						}
						
						// If still not colliding
						if (!GrippedActors[i].bColliding)
						{
							if (bIsServer && actor->bReplicateMovement) // So we don't call on on change event over and over locally
								actor->SetReplicateMovement(false);

							if (bIsServer && GripHandle)
							{
								DestroyPhysicsHandle(GrippedActors[i]);

								if(GrippedActors[i].Actor)
									GrippedActors[i].Actor->DisableComponentsSimulatePhysics();
								else
									root->SetSimulatePhysics(false);
							}

							root->SetWorldTransform(WorldTransform, false);
						}
						else
						{
							if (bIsServer && GrippedActors[i].bColliding && GripHandle)
								UpdatePhysicsHandleTransform(GrippedActors[i], WorldTransform);
						}

					}
					else if (GrippedActors[i].bColliding && !GripHandle)
					{
						if (bIsServer && !actor->bReplicateMovement)
							actor->SetReplicateMovement(true);

						root->SetSimulatePhysics(true);

						if (bIsServer)
							SetUpPhysicsHandle(GrippedActors[i]);
					}
					else
					{
						if (bIsServer && GrippedActors[i].bColliding && GripHandle)
							UpdatePhysicsHandleTransform(GrippedActors[i], WorldTransform);
					}
				}
				else if (GrippedActors[i].GripCollisionType == EGripCollisionType::SweepWithPhysics)
				{
					if (bIsServer)
					{
						
						FVector OriginalPosition(root->GetComponentLocation());
						FRotator OriginalOrientation(root->GetComponentRotation());

						FVector NewPosition(WorldTransform.GetTranslation());
						FRotator NewOrientation(WorldTransform.GetRotation());

						// Now sweep collision separately so we can get hits but not have the location altered
						if (bUseWithoutTracking || NewPosition != OriginalPosition || NewOrientation != OriginalOrientation)
						{
							FVector move = NewPosition - OriginalPosition;

							// ComponentSweepMulti does nothing if moving < KINDA_SMALL_NUMBER in distance, so it's important to not try to sweep distances smaller than that. 
							const float MinMovementDistSq = (FMath::Square(4.f*KINDA_SMALL_NUMBER));

							if (bUseWithoutTracking || move.SizeSquared() > MinMovementDistSq || NewOrientation != OriginalOrientation)
							{
								if (CheckComponentWithSweep(root, move, NewOrientation, false))
								{

								}
							}
						}

						// Move the actor, we are not offsetting by the hit result anyway
						root->SetWorldTransform(WorldTransform, false);
					}
					else
					{
						// Move the actor, we are not offsetting by the hit result anyway
						root->SetWorldTransform(WorldTransform, false);
					}
				}
				else if (GrippedActors[i].GripCollisionType == EGripCollisionType::PhysicsOnly)
				{
					// Move the actor, we are not offsetting by the hit result anyway
					root->SetWorldTransform(WorldTransform, false);
				}
			}
			else
			{
				if (bIsServer)
				{
					DestroyPhysicsHandle(GrippedActors[i]);

					GrippedActors.RemoveAt(i); // If it got garbage collected then just remove the pointer, won't happen with new uproperty use, but keeping it here anyway
				}
			}

		}
	}

}
void FAnimNode_CopyBoneDelta::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, FCSPose<FCompactPose>& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
	if(!bCopyTranslation && !bCopyRotation && !bCopyScale)
	{
		return;
	}

	const FBoneContainer& BoneContainer = MeshBases.GetPose().GetBoneContainer();
	FCompactPoseBoneIndex SourceBoneIndex = SourceBone.GetCompactPoseIndex(BoneContainer);
	FCompactPoseBoneIndex TargetBoneIndex = TargetBone.GetCompactPoseIndex(BoneContainer);

	FTransform SourceTM = MeshBases.GetComponentSpaceTransform(SourceBoneIndex);
	FTransform TargetTM = MeshBases.GetComponentSpaceTransform(TargetBoneIndex);

	// Convert to parent space
	FAnimationRuntime::ConvertCSTransformToBoneSpace(SkelComp, MeshBases, SourceTM, SourceBoneIndex, BCS_ParentBoneSpace);
	FAnimationRuntime::ConvertCSTransformToBoneSpace(SkelComp, MeshBases, TargetTM, TargetBoneIndex, BCS_ParentBoneSpace);

	// Ref pose transform
	FTransform RefLSTransform = SkelComp->SkeletalMesh->RefSkeleton.GetRefBonePose()[SourceBone.GetMeshPoseIndex().GetInt()];

	// Get transform relative to ref pose
	SourceTM.SetToRelativeTransform(RefLSTransform);

	if(CopyMode == CopyBoneDeltaMode::Accumulate)
	{
		if(bCopyTranslation)
		{
			TargetTM.AddToTranslation(SourceTM.GetTranslation() * TranslationMultiplier);
		}
		if(bCopyRotation)
		{
			FVector Axis;
			float Angle;
			SourceTM.GetRotation().ToAxisAndAngle(Axis, Angle);

			TargetTM.SetRotation(FQuat(Axis, Angle * RotationMultiplier) * TargetTM.GetRotation());
		}
		if(bCopyScale)
		{
			TargetTM.SetScale3D(TargetTM.GetScale3D() * (SourceTM.GetScale3D() * ScaleMultiplier));
		}
	}
	else //CopyMode = CopyBoneDeltaMode::Copy
	{
		if(bCopyTranslation)
		{
			TargetTM.SetTranslation(SourceTM.GetTranslation() * TranslationMultiplier);
		}

		if(bCopyRotation)
		{
			FVector Axis;
			float Angle;
			SourceTM.GetRotation().ToAxisAndAngle(Axis, Angle);

			TargetTM.SetRotation(FQuat(Axis, Angle * RotationMultiplier));
		}

		if(bCopyScale)
		{
			TargetTM.SetScale3D(SourceTM.GetScale3D() * ScaleMultiplier);
		}
	}

	// Back out to component space
	FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, TargetTM, TargetBoneIndex, BCS_ParentBoneSpace);

	OutBoneTransforms.Add(FBoneTransform(TargetBoneIndex, TargetTM));
}
FString UKismetStringLibrary::Conv_TransformToString(const FTransform& InTrans)
{
	return FString::Printf(TEXT("Translation: %s Rotation: %s Scale %s"), *InTrans.GetTranslation().ToString(), *InTrans.Rotator().ToString(), *InTrans.GetScale3D().ToString());
}
Example #26
0
/** Extract RootMotion Transform from a contiguous Track position range.
 * *CONTIGUOUS* means that if playing forward StartTractPosition < EndTrackPosition.
 * No wrapping over if looping. No jumping across different sections.
 * So the AnimMontage has to break the update into contiguous pieces to handle those cases.
 *
 * This does handle Montage playing backwards (StartTrackPosition > EndTrackPosition).
 *
 * It will break down the range into steps if needed to handle looping animations, or different animations.
 * These steps will be processed sequentially, and output the RootMotion transform in component space.
 */
FTransform UAnimMontage::ExtractRootMotionFromTrackRange(float StartTrackPosition, float EndTrackPosition) const
{
	FRootMotionMovementParams RootMotion;

	// For now assume Root Motion only comes from first track.
	if( SlotAnimTracks.Num() > 0 )
	{
		const FAnimTrack& SlotAnimTrack = SlotAnimTracks[0].AnimTrack;

		// Get RootMotion pieces from this track.
		// We can deal with looping animations, or multiple animations. So we break those up into sequential operations.
		// (Animation, StartFrame, EndFrame) so we can then extract root motion sequentially.
		TArray<FRootMotionExtractionStep> RootMotionExtractionSteps;
		SlotAnimTrack.GetRootMotionExtractionStepsForTrackRange(RootMotionExtractionSteps, StartTrackPosition, EndTrackPosition);

		UE_LOG(LogRootMotion, Log,  TEXT("\tUAnimMontage::ExtractRootMotionForTrackRange, NumSteps: %d, StartTrackPosition: %.3f, EndTrackPosition: %.3f"), 
			RootMotionExtractionSteps.Num(), StartTrackPosition, EndTrackPosition);

		// Process root motion steps if any
		if( RootMotionExtractionSteps.Num() > 0 )
		{
			FTransform InitialTransform, StartTransform, EndTransform;

			// Go through steps sequentially, extract root motion, and accumulate it.
			// This has to be done in order so root motion translation & rotation is applied properly (as translation is relative to rotation)
			for(int32 StepIndex=0; StepIndex<RootMotionExtractionSteps.Num(); StepIndex++)
			{
				const FRootMotionExtractionStep& CurrentStep = RootMotionExtractionSteps[StepIndex];
				CurrentStep.AnimSequence->ExtractRootTrack(0.f, InitialTransform, NULL);
				CurrentStep.AnimSequence->ExtractRootTrack(CurrentStep.StartPosition, StartTransform, NULL);
				CurrentStep.AnimSequence->ExtractRootTrack(CurrentStep.EndPosition, EndTransform, NULL);
				
				// Transform to Component Space Rotation (inverse root transform from first frame)
				const FTransform RootToComponentRot = FTransform(InitialTransform.GetRotation().Inverse());
				StartTransform = RootToComponentRot * StartTransform;
				EndTransform = RootToComponentRot * EndTransform;

				FTransform DeltaTransform = EndTransform.GetRelativeTransform(StartTransform);

				// Filter out rotation 
				if( !bEnableRootMotionRotation )
				{
					DeltaTransform.SetRotation(FQuat::Identity);
				}
				// Filter out translation
				if( !bEnableRootMotionTranslation )
				{
					DeltaTransform.SetTranslation(FVector::ZeroVector);
				}

				RootMotion.Accumulate(DeltaTransform);

				UE_LOG(LogRootMotion, Log,  TEXT("\t\tCurrentStep: %d, StartPos: %.3f, EndPos: %.3f, Anim: %s DeltaTransform Translation: %s, Rotation: %s"),
					StepIndex, CurrentStep.StartPosition, CurrentStep.EndPosition, *CurrentStep.AnimSequence->GetName(), 
					*DeltaTransform.GetTranslation().ToCompactString(), *DeltaTransform.GetRotation().Rotator().ToCompactString() );
			}
		}
	}

	UE_LOG(LogRootMotion, Log,  TEXT("\tUAnimMontage::ExtractRootMotionForTrackRange RootMotionTransform: Translation: %s, Rotation: %s"),
		*RootMotion.RootMotionTransform.GetTranslation().ToCompactString(), *RootMotion.RootMotionTransform.GetRotation().Rotator().ToCompactString() );

	return RootMotion.RootMotionTransform;
}
bool UAnimExporterITP::ExportText(const FExportObjectInnerContext* Context, UObject* Object, const TCHAR* Type, FOutputDevice& Ar, FFeedbackContext* Warn, uint32 PortFlags /*= 0*/)
{
	UAnimSequence* AnimSeq = CastChecked<UAnimSequence>(Object);

	USkeleton* Skeleton = AnimSeq->GetSkeleton();
	const FReferenceSkeleton& RefSkeleton = Skeleton->GetReferenceSkeleton();
	USkeletalMesh* SkelMesh = Skeleton->GetPreviewMesh();
	if (AnimSeq->SequenceLength == 0.f)
	{
		// something is wrong
		return false;
	}

	const float FrameRate = AnimSeq->NumFrames / AnimSeq->SequenceLength;

	// Open another archive
	FArchive* File = IFileManager::Get().CreateFileWriter(*UExporter::CurrentFilename);

	// Let's try the header...
	File->Logf(TEXT("{"));
	File->Logf(TEXT("\t\"metadata\":{"));
	File->Logf(TEXT("\t\t\"type\":\"itpanim\","));
	File->Logf(TEXT("\t\t\"version\":2"));
	File->Logf(TEXT("\t},"));

	File->Logf(TEXT("\t\"sequence\":{"));
	File->Logf(TEXT("\t\t\"frames\":%d,"), AnimSeq->NumFrames);
	File->Logf(TEXT("\t\t\"length\":%f,"), AnimSeq->SequenceLength);
	File->Logf(TEXT("\t\t\"bonecount\":%d,"), RefSkeleton.GetNum());
	File->Logf(TEXT("\t\t\"tracks\":["));

	bool firstOutput = false;

	for (int32 BoneIndex = 0; BoneIndex < RefSkeleton.GetNum(); ++BoneIndex)
	{
		//int32 BoneTreeIndex = Skeleton->GetSkeletonBoneIndexFromMeshBoneIndex(SkelMesh, BoneIndex);
		int32 BoneTrackIndex = Skeleton->GetAnimationTrackIndex(BoneIndex, AnimSeq);
		
		if (BoneTrackIndex == INDEX_NONE)
		{
			// If this sequence does not have a track for the current bone, then skip it
			continue;
		}
	
		if (firstOutput)
		{
			File->Logf(TEXT("\t\t\t},"));
		}

		firstOutput = true;

		File->Logf(TEXT("\t\t\t{"));
		File->Logf(TEXT("\t\t\t\t\"bone\":%d,"), BoneIndex);
		File->Logf(TEXT("\t\t\t\t\"transforms\":["));
		float AnimTime = 0.0f;
		float AnimEndTime = AnimSeq->SequenceLength;
		// Subtracts 1 because NumFrames includes an initial pose for 0.0 second
		double TimePerKey = (AnimSeq->SequenceLength / (AnimSeq->NumFrames - 1));
		const float AnimTimeIncrement = TimePerKey;

		bool bLastKey = false;
		// Step through each frame and add the bone's transformation data
		while (!bLastKey)
		{
			const TArray<FBoneNode>& BoneTree = Skeleton->GetBoneTree();

			FTransform BoneAtom;
			AnimSeq->GetBoneTransform(BoneAtom, BoneTrackIndex, AnimTime, true);

			bLastKey = AnimTime >= AnimEndTime;

			File->Logf(TEXT("\t\t\t\t\t{"));

			FQuat rot = BoneAtom.GetRotation();
			// For the root bone, we need to fix-up the rotation because Unreal exports
			// animations with Y-forward for some reason (maybe because Maya?)
			if (BoneIndex == 0)
			{
				FQuat addRot(FVector(0.0f, 0.0f, 1.0f), -1.57f);
				rot = addRot * rot;
			}
			File->Logf(TEXT("\t\t\t\t\t\t\"rot\":[%f,%f,%f,%f],"), rot.X, rot.Y, rot.Z, rot.W);
			FVector trans = BoneAtom.GetTranslation();

			// Sanjay: If it's skeleton retargeting, change the translation to be from the ref pose skeleton
			if (BoneTree[BoneIndex].TranslationRetargetingMode == EBoneTranslationRetargetingMode::Skeleton)
			{
				const FTransform& BoneTransform = RefSkeleton.GetRefBonePose()[BoneIndex];
				trans = BoneTransform.GetTranslation();
			}

			File->Logf(TEXT("\t\t\t\t\t\t\"trans\":[%f,%f,%f]"), trans.X, trans.Y, trans.Z);

			if (!bLastKey)
			{
				File->Logf(TEXT("\t\t\t\t\t},"));
			}
			else
			{
				File->Logf(TEXT("\t\t\t\t\t}"));
			}
			

			AnimTime += AnimTimeIncrement;
		}

		File->Logf(TEXT("\t\t\t\t]"), BoneIndex);
	}

	File->Logf(TEXT("\t\t\t}"));
	File->Logf(TEXT("\t\t]"));
	File->Logf(TEXT("\t}"));

 	File->Logf(TEXT("}"));
 	delete File;

	return true;
}
Example #28
0
void FAnimNode_Trail::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer& RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
	check(OutBoneTransforms.Num() == 0);

	if( ChainLength < 2 )
	{
		return;
	}

	// The incoming BoneIndex is the 'end' of the spline chain. We need to find the 'start' by walking SplineLength bones up hierarchy.
	// Fail if we walk past the root bone.

	int32 WalkBoneIndex = TrailBone.BoneIndex;

	TArray<int32> ChainBoneIndices;
	ChainBoneIndices.AddZeroed(ChainLength);

	ChainBoneIndices[ChainLength - 1] = WalkBoneIndex;

	for (int32 i = 1; i < ChainLength; i++)
	{
		// returns to avoid a crash
		// @TODO : shows an error message why failed
		if (WalkBoneIndex == 0)
		{
			return;
		}

		// Get parent bone.
		WalkBoneIndex = RequiredBones.GetParentBoneIndex(WalkBoneIndex);

		//Insert indices at the start of array, so that parents are before children in the array.
		int32 TransformIndex = ChainLength - (i + 1);
		ChainBoneIndices[TransformIndex] = WalkBoneIndex;
	}

	OutBoneTransforms.AddZeroed(ChainLength);

	// If we have >0 this frame, but didn't last time, record positions of all the bones.
	// Also do this if number has changed or array is zero.
	bool bHasValidStrength = (Alpha > 0.f);
	if(TrailBoneLocations.Num() != ChainLength || (bHasValidStrength && !bHadValidStrength))
	{
		TrailBoneLocations.Empty();
		TrailBoneLocations.AddZeroed(ChainLength);

		for(int32 i=0; i<ChainBoneIndices.Num(); i++)
		{
			int32 ChildIndex = ChainBoneIndices[i];
			FTransform ChainTransform = MeshBases.GetComponentSpaceTransform(ChildIndex);
			TrailBoneLocations[i] = ChainTransform.GetTranslation();
		}
		OldLocalToWorld = SkelComp->GetTransformMatrix();
	}
	bHadValidStrength = bHasValidStrength;

	// transform between last frame and now.
	FMatrix OldToNewTM = OldLocalToWorld * SkelComp->GetTransformMatrix().InverseFast();

	// Add fake velocity if present to all but root bone
	if(!FakeVelocity.IsZero())
	{
		FVector FakeMovement = -FakeVelocity * ThisTimstep;

		if (bActorSpaceFakeVel && SkelComp->GetOwner())
		{
			const FTransform BoneToWorld(SkelComp->GetOwner()->GetActorRotation(), SkelComp->GetOwner()->GetActorLocation());
			FakeMovement = BoneToWorld.TransformVector(FakeMovement);
		}

		FakeMovement = SkelComp->GetTransformMatrix().InverseTransformVector(FakeMovement);
		// Then add to each bone
		for(int32 i=1; i<TrailBoneLocations.Num(); i++)
		{
			TrailBoneLocations[i] += FakeMovement;
		}
	}

	// Root bone of trail is not modified.
	int32 RootIndex = ChainBoneIndices[0]; 
	FTransform ChainTransform = MeshBases.GetComponentSpaceTransform(RootIndex);
	OutBoneTransforms[0] = FBoneTransform(RootIndex, ChainTransform);
	TrailBoneLocations[0] = ChainTransform.GetTranslation();

	// Starting one below head of chain, move bones.
	for(int32 i=1; i<ChainBoneIndices.Num(); i++)
	{
		// Parent bone position in component space.
		int32 ParentIndex = ChainBoneIndices[i-1];
		FVector ParentPos = TrailBoneLocations[i-1];
		FVector ParentAnimPos = MeshBases.GetComponentSpaceTransform(ParentIndex).GetTranslation();

		// Child bone position in component space.
		int32 ChildIndex = ChainBoneIndices[i];
		FVector ChildPos = OldToNewTM.TransformPosition(TrailBoneLocations[i]); // move from 'last frames component' frame to 'this frames component' frame
		FVector ChildAnimPos = MeshBases.GetComponentSpaceTransform(ChildIndex).GetTranslation();

		// Desired parent->child offset.
		FVector TargetDelta = (ChildAnimPos - ParentAnimPos);

		// Desired child position.
		FVector ChildTarget = ParentPos + TargetDelta;

		// Find vector from child to target
		FVector Error = ChildTarget - ChildPos;

		// Calculate how much to push the child towards its target
		float Correction = FMath::Clamp<float>(ThisTimstep * TrailRelaxation, 0.f, 1.f);

		// Scale correction vector and apply to get new world-space child position.
		TrailBoneLocations[i] = ChildPos + (Error * Correction);

		// If desired, prevent bones stretching too far.
		if(bLimitStretch)
		{
			float RefPoseLength = TargetDelta.Size();
			FVector CurrentDelta = TrailBoneLocations[i] - TrailBoneLocations[i-1];
			float CurrentLength = CurrentDelta.Size();

			// If we are too far - cut it back (just project towards parent particle).
			if( (CurrentLength - RefPoseLength > StretchLimit) && CurrentLength > SMALL_NUMBER )
			{
				FVector CurrentDir = CurrentDelta / CurrentLength;
				TrailBoneLocations[i] = TrailBoneLocations[i-1] + (CurrentDir * (RefPoseLength + StretchLimit));
			}
		}

		// Modify child matrix
		OutBoneTransforms[i] = FBoneTransform(ChildIndex, MeshBases.GetComponentSpaceTransform(ChildIndex));
		OutBoneTransforms[i].Transform.SetTranslation(TrailBoneLocations[i]);

		// Modify rotation of parent matrix to point at this one.

		// Calculate the direction that parent bone is currently pointing.
		FVector CurrentBoneDir = OutBoneTransforms[i-1].Transform.TransformVector( GetAlignVector(ChainBoneAxis, bInvertChainBoneAxis) );
		CurrentBoneDir = CurrentBoneDir.SafeNormal(SMALL_NUMBER);

		// Calculate vector from parent to child.
		FVector NewBoneDir = FVector(OutBoneTransforms[i].Transform.GetTranslation() - OutBoneTransforms[i - 1].Transform.GetTranslation()).SafeNormal(SMALL_NUMBER);

		// Calculate a quaternion that gets us from our current rotation to the desired one.
		FQuat DeltaLookQuat = FQuat::FindBetween(CurrentBoneDir, NewBoneDir);
		FTransform DeltaTM( DeltaLookQuat, FVector(0.f) );

		// Apply to the current parent bone transform.
		FTransform TmpMatrix = FTransform::Identity;
		TmpMatrix.CopyRotationPart(OutBoneTransforms[i - 1].Transform);
		TmpMatrix = TmpMatrix * DeltaTM;
		OutBoneTransforms[i - 1].Transform.CopyRotationPart(TmpMatrix);
	}

	// For the last bone in the chain, use the rotation from the bone above it.
	OutBoneTransforms[ChainLength - 1].Transform.CopyRotationPart(OutBoneTransforms[ChainLength - 2].Transform);

	// Update OldLocalToWorld
	OldLocalToWorld = SkelComp->GetTransformMatrix();
}
void FAnimNode_TwoBoneIK::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer & RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
	check(OutBoneTransforms.Num() == 0);

	// Get indices of the lower and upper limb bones and check validity.
	bool bInvalidLimb = false;

	const int32 EndBoneIndex = IKBone.BoneIndex;
	const int32 LowerLimbIndex = RequiredBones.GetParentBoneIndex(EndBoneIndex);
	if (LowerLimbIndex == INDEX_NONE)
	{
		bInvalidLimb = true;
	}

	const int32 UpperLimbIndex = RequiredBones.GetParentBoneIndex(LowerLimbIndex);
	if (UpperLimbIndex == INDEX_NONE)
	{
		bInvalidLimb = true;
	}

	const bool bInBoneSpace = (EffectorLocationSpace == BCS_ParentBoneSpace) || (EffectorLocationSpace == BCS_BoneSpace);
	const int32 EffectorSpaceBoneIndex = bInBoneSpace ? RequiredBones.GetPoseBoneIndexForBoneName(EffectorSpaceBoneName) : INDEX_NONE;

	if (bInBoneSpace && ((EffectorSpaceBoneIndex == INDEX_NONE) || !RequiredBones.Contains(EffectorSpaceBoneIndex)))
	{
		bInvalidLimb = true;
	}

	// If we walked past the root, this controlled is invalid, so return no affected bones.
	if( bInvalidLimb )
	{
		return;
	}

	// Get Local Space transforms for our bones. We do this first in case they already are local.
	// As right after we get them in component space. (And that does the auto conversion).
	// We might save one transform by doing local first...
	const FTransform EndBoneLocalTransform = MeshBases.GetLocalSpaceTransform(IKBone.BoneIndex);

	// Now get those in component space...
	FTransform UpperLimbCSTransform = MeshBases.GetComponentSpaceTransform(UpperLimbIndex);
	FTransform LowerLimbCSTransform = MeshBases.GetComponentSpaceTransform(LowerLimbIndex);
	FTransform EndBoneCSTransform = MeshBases.GetComponentSpaceTransform(IKBone.BoneIndex);

	// Get current position of root of limb.
	// All position are in Component space.
	const FVector RootPos = UpperLimbCSTransform.GetTranslation();
	const FVector InitialJointPos = LowerLimbCSTransform.GetTranslation();
	const FVector InitialEndPos = EndBoneCSTransform.GetTranslation();

	// Transform EffectorLocation from EffectorLocationSpace to ComponentSpace.
	FTransform EffectorTransform(EffectorLocation);
	FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, EffectorTransform, EffectorSpaceBoneIndex, EffectorLocationSpace);

	// This is our reach goal.
	FVector DesiredPos = EffectorTransform.GetTranslation();
	FVector DesiredDelta = DesiredPos - RootPos;
	float DesiredLength = DesiredDelta.Size();

	// Check to handle case where DesiredPos is the same as RootPos.
	FVector	DesiredDir;
	if (DesiredLength < (float)KINDA_SMALL_NUMBER)
	{
		DesiredLength = (float)KINDA_SMALL_NUMBER;
		DesiredDir = FVector(1,0,0);
	}
	else
	{
		DesiredDir = DesiredDelta / DesiredLength;
	}

	// Get joint target (used for defining plane that joint should be in).
	FTransform JointTargetTransform(JointTargetLocation);
	const int32 JointTargetSpaceBoneIndex = (JointTargetLocationSpace == BCS_ParentBoneSpace || JointTargetLocationSpace == BCS_BoneSpace) ? RequiredBones.GetPoseBoneIndexForBoneName(JointTargetSpaceBoneName) : INDEX_NONE;
	FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, JointTargetTransform, JointTargetSpaceBoneIndex, JointTargetLocationSpace);

	FVector	JointTargetPos = JointTargetTransform.GetTranslation();
	FVector JointTargetDelta = JointTargetPos - RootPos;
	float JointTargetLength = JointTargetDelta.Size();

	// Same check as above, to cover case when JointTarget position is the same as RootPos.
	FVector JointPlaneNormal, JointBendDir;
	if (JointTargetLength < (float)KINDA_SMALL_NUMBER)
	{
		JointBendDir = FVector(0,1,0);
		JointPlaneNormal = FVector(0,0,1);
	}
	else
	{
		JointPlaneNormal = DesiredDir ^ JointTargetDelta;

		// If we are trying to point the limb in the same direction that we are supposed to displace the joint in, 
		// we have to just pick 2 random vector perp to DesiredDir and each other.
		if (JointPlaneNormal.Size() < (float)KINDA_SMALL_NUMBER)
		{
			DesiredDir.FindBestAxisVectors(JointPlaneNormal, JointBendDir);
		}
		else
		{
			JointPlaneNormal.Normalize();

			// Find the final member of the reference frame by removing any component of JointTargetDelta along DesiredDir.
			// This should never leave a zero vector, because we've checked DesiredDir and JointTargetDelta are not parallel.
			JointBendDir = JointTargetDelta - ((JointTargetDelta | DesiredDir) * DesiredDir);
			JointBendDir.Normalize();
		}
	}

	// Find lengths of upper and lower limb in the ref skeleton.
	// Use actual sizes instead of ref skeleton, so we take into account translation and scaling from other bone controllers.
	float LowerLimbLength = (InitialEndPos - InitialJointPos).Size();
	float UpperLimbLength = (InitialJointPos - RootPos).Size();
	float MaxLimbLength	= LowerLimbLength + UpperLimbLength;

	if (bAllowStretching)
	{
		const float ScaleRange = StretchLimits.Y - StretchLimits.X;
		if( ScaleRange > KINDA_SMALL_NUMBER && MaxLimbLength > KINDA_SMALL_NUMBER )
		{
			const float ReachRatio = DesiredLength / MaxLimbLength;
			const float ScalingFactor = (StretchLimits.Y - 1.f) * FMath::Clamp<float>((ReachRatio - StretchLimits.X) / ScaleRange, 0.f, 1.f);
			if (ScalingFactor > KINDA_SMALL_NUMBER)
			{
				LowerLimbLength *= (1.f + ScalingFactor);
				UpperLimbLength *= (1.f + ScalingFactor);
				MaxLimbLength	*= (1.f + ScalingFactor);
			}
		}
	}

	FVector OutEndPos = DesiredPos;
	FVector OutJointPos = InitialJointPos;

	// If we are trying to reach a goal beyond the length of the limb, clamp it to something solvable and extend limb fully.
	if (DesiredLength > MaxLimbLength)
	{
		OutEndPos = RootPos + (MaxLimbLength * DesiredDir);
		OutJointPos = RootPos + (UpperLimbLength * DesiredDir);
	}
	else
	{
		// So we have a triangle we know the side lengths of. We can work out the angle between DesiredDir and the direction of the upper limb
		// using the sin rule:
		const float TwoAB = 2.f * UpperLimbLength * DesiredLength;

		const float CosAngle = (TwoAB != 0.f) ? ((UpperLimbLength*UpperLimbLength) + (DesiredLength*DesiredLength) - (LowerLimbLength*LowerLimbLength)) / TwoAB : 0.f;

		// If CosAngle is less than 0, the upper arm actually points the opposite way to DesiredDir, so we handle that.
		const bool bReverseUpperBone = (CosAngle < 0.f);

		// If CosAngle is greater than 1.f, the triangle could not be made - we cannot reach the target.
		// We just have the two limbs double back on themselves, and EndPos will not equal the desired EffectorLocation.
		if ((CosAngle > 1.f) || (CosAngle < -1.f))
		{
			// Because we want the effector to be a positive distance down DesiredDir, we go back by the smaller section.
			if (UpperLimbLength > LowerLimbLength)
			{
				OutJointPos = RootPos + (UpperLimbLength * DesiredDir);
				OutEndPos = OutJointPos - (LowerLimbLength * DesiredDir);
			}
			else
			{
				OutJointPos = RootPos - (UpperLimbLength * DesiredDir);
				OutEndPos = OutJointPos + (LowerLimbLength * DesiredDir);
			}
		}
		else
		{
			// Angle between upper limb and DesiredDir
			const float Angle = FMath::Acos(CosAngle);

			// Now we calculate the distance of the joint from the root -> effector line.
			// This forms a right-angle triangle, with the upper limb as the hypotenuse.
			const float JointLineDist = UpperLimbLength * FMath::Sin(Angle);

			// And the final side of that triangle - distance along DesiredDir of perpendicular.
			// ProjJointDistSqr can't be neg, because JointLineDist must be <= UpperLimbLength because appSin(Angle) is <= 1.
			const float ProjJointDistSqr = (UpperLimbLength*UpperLimbLength) - (JointLineDist*JointLineDist);
			// although this shouldn't be ever negative, sometimes Xbox release produces -0.f, causing ProjJointDist to be NaN
			// so now I branch it. 						
			float ProjJointDist = (ProjJointDistSqr>0.f)? FMath::Sqrt(ProjJointDistSqr) : 0.f;
			if( bReverseUpperBone )
			{
				ProjJointDist *= -1.f;
			}

			// So now we can work out where to put the joint!
			OutJointPos = RootPos + (ProjJointDist * DesiredDir) + (JointLineDist * JointBendDir);
		}
	}

	// Update transform for upper bone.
	{
		// Get difference in direction for old and new joint orientations
		FVector const OldDir = (InitialJointPos - RootPos).SafeNormal();
		FVector const NewDir = (OutJointPos - RootPos).SafeNormal();
		// Find Delta Rotation take takes us from Old to New dir
		FQuat const DeltaRotation = FQuat::FindBetween(OldDir, NewDir);
		// Rotate our Joint quaternion by this delta rotation
		UpperLimbCSTransform.SetRotation( DeltaRotation * UpperLimbCSTransform.GetRotation() );
		// And put joint where it should be.
		UpperLimbCSTransform.SetTranslation( RootPos );

		// Order important. First bone is upper limb.
		OutBoneTransforms.Add( FBoneTransform(UpperLimbIndex, UpperLimbCSTransform) );
	}

	// Update transform for lower bone.
	{
		// Get difference in direction for old and new joint orientations
		FVector const OldDir = (InitialEndPos - InitialJointPos).SafeNormal();
		FVector const NewDir = (OutEndPos - OutJointPos).SafeNormal();

		// Find Delta Rotation take takes us from Old to New dir
		FQuat const DeltaRotation = FQuat::FindBetween(OldDir, NewDir);
		// Rotate our Joint quaternion by this delta rotation
		LowerLimbCSTransform.SetRotation( DeltaRotation * LowerLimbCSTransform.GetRotation() );
		// And put joint where it should be.
		LowerLimbCSTransform.SetTranslation( OutJointPos );

		// Order important. Second bone is lower limb.
		OutBoneTransforms.Add( FBoneTransform(LowerLimbIndex, LowerLimbCSTransform) );
	}

	// Update transform for end bone.
	{
		if( bTakeRotationFromEffectorSpace )
		{
			EndBoneCSTransform.SetRotation( EffectorTransform.GetRotation() );
		}
		else if( bMaintainEffectorRelRot )
		{
			EndBoneCSTransform = EndBoneLocalTransform * LowerLimbCSTransform;
		}

		// Set correct location for end bone.
		EndBoneCSTransform.SetTranslation(OutEndPos);

		// Order important. Third bone is End Bone.
		OutBoneTransforms.Add( FBoneTransform(IKBone.BoneIndex, EndBoneCSTransform) );
	}

	// Make sure we have correct number of bones
	check(OutBoneTransforms.Num() == 3);
}
bool UnFbx::FFbxImporter::ImportAnimation(USkeleton* Skeleton, UAnimSequence * DestSeq, const FString& FileName, TArray<FbxNode*>& SortedLinks, TArray<FbxNode*>& NodeArray, FbxAnimStack* CurAnimStack, const int32 ResampleRate, const FbxTimeSpan AnimTimeSpan)
{
	// @todo : the length might need to change w.r.t. sampling keys
	FbxTime SequenceLength = AnimTimeSpan.GetDuration();
	float PreviousSequenceLength = DestSeq->SequenceLength;

	// if you have one pose(thus 0.f duration), it still contains animation, so we'll need to consider that as MINIMUM_ANIMATION_LENGTH time length
	DestSeq->SequenceLength = FGenericPlatformMath::Max<float>(SequenceLength.GetSecondDouble(), MINIMUM_ANIMATION_LENGTH);

	if(PreviousSequenceLength > MINIMUM_ANIMATION_LENGTH && DestSeq->RawCurveData.FloatCurves.Num() > 0)
	{
		// The sequence already existed when we began the import. We need to scale the key times for all curves to match the new 
		// duration before importing over them. This is to catch any user-added curves
		float ScaleFactor = DestSeq->SequenceLength / PreviousSequenceLength;
		for(FFloatCurve& Curve : DestSeq->RawCurveData.FloatCurves)
		{
			Curve.FloatCurve.ScaleCurve(0.0f, ScaleFactor);
		}
	}

	if (ImportOptions->bDeleteExistingMorphTargetCurves)
	{
		for (int32 CurveIdx=0; CurveIdx<DestSeq->RawCurveData.FloatCurves.Num(); ++CurveIdx)
		{
			auto& Curve = DestSeq->RawCurveData.FloatCurves[CurveIdx];
			if (Curve.GetCurveTypeFlag(ACF_DrivesMorphTarget))
			{
				DestSeq->RawCurveData.FloatCurves.RemoveAt(CurveIdx, 1, false);
				--CurveIdx;
			}
		}

		DestSeq->RawCurveData.FloatCurves.Shrink();
	}

	//
	// import blend shape curves
	//
	{
		GWarn->BeginSlowTask( LOCTEXT("BeginImportMorphTargetCurves", "Importing Morph Target Curves"), true);
		for ( int32 NodeIndex = 0; NodeIndex < NodeArray.Num(); NodeIndex++ )
		{
			// consider blendshape animation curve
			FbxGeometry* Geometry = (FbxGeometry*)NodeArray[NodeIndex]->GetNodeAttribute();
			if (Geometry)
			{
				int32 BlendShapeDeformerCount = Geometry->GetDeformerCount(FbxDeformer::eBlendShape);
				for(int32 BlendShapeIndex = 0; BlendShapeIndex<BlendShapeDeformerCount; ++BlendShapeIndex)
				{
					FbxBlendShape* BlendShape = (FbxBlendShape*)Geometry->GetDeformer(BlendShapeIndex, FbxDeformer::eBlendShape);

					const int32 BlendShapeChannelCount = BlendShape->GetBlendShapeChannelCount();

					FString BlendShapeName = UTF8_TO_TCHAR(MakeName(BlendShape->GetName()));

					for(int32 ChannelIndex = 0; ChannelIndex<BlendShapeChannelCount; ++ChannelIndex)
					{
						FbxBlendShapeChannel* Channel = BlendShape->GetBlendShapeChannel(ChannelIndex);

						if(Channel)
						{
							FString ChannelName = UTF8_TO_TCHAR(MakeName(Channel->GetName()));

							// Maya adds the name of the blendshape and an underscore to the front of the channel name, so remove it
							if(ChannelName.StartsWith(BlendShapeName))
							{
								ChannelName = ChannelName.Right(ChannelName.Len() - (BlendShapeName.Len()+1));
							}

							FbxAnimCurve* Curve = Geometry->GetShapeChannel(BlendShapeIndex, ChannelIndex, (FbxAnimLayer*)CurAnimStack->GetMember(0));
							if (Curve && Curve->KeyGetCount() > 0)
							{
								FFormatNamedArguments Args;
								Args.Add(TEXT("BlendShape"), FText::FromString(ChannelName));
								const FText StatusUpate = FText::Format(LOCTEXT("ImportingMorphTargetCurvesDetail", "Importing Morph Target Curves [{BlendShape}]"), Args);
								GWarn->StatusUpdate(NodeIndex + 1, NodeArray.Num(), StatusUpate);
								// now see if we have one already exists. If so, just overwrite that. if not, add new one. 
								ImportCurveToAnimSequence(DestSeq, *ChannelName, Curve,  ACF_DrivesMorphTarget | ACF_TriggerEvent, AnimTimeSpan, 0.01f /** for some reason blend shape values are coming as 100 scaled **/);
							}
						}
					}
				}
			}
		}
		GWarn->EndSlowTask();
	}

	// 
	// importing custom attribute START
	//
	if (ImportOptions->bImportCustomAttribute)
	{
		GWarn->BeginSlowTask( LOCTEXT("BeginImportMorphTargetCurves", "Importing Custom Attirubte Curves"), true);
		const int32 TotalLinks = SortedLinks.Num();
		int32 CurLinkIndex=0;
		for(auto Node: SortedLinks)
		{
			FbxProperty Property = Node->GetFirstProperty();
			while (Property.IsValid())
			{
				FbxAnimCurveNode* CurveNode = Property.GetCurveNode();
				// do this if user defined and animated and leaf node
				if( CurveNode && Property.GetFlag(FbxPropertyAttr::eUserDefined) && 
					CurveNode->IsAnimated() && IsSupportedCurveDataType(Property.GetPropertyDataType().GetType()) )
				{
					FString CurveName = UTF8_TO_TCHAR(CurveNode->GetName());
					UE_LOG(LogFbx, Log, TEXT("CurveName : %s"), *CurveName );

					int32 TotalCount = CurveNode->GetChannelsCount();
					for (int32 ChannelIndex=0; ChannelIndex<TotalCount; ++ChannelIndex)
					{
						FbxAnimCurve * AnimCurve = CurveNode->GetCurve(ChannelIndex);
						FString ChannelName = CurveNode->GetChannelName(ChannelIndex).Buffer();

						if (AnimCurve)
						{
							FString FinalCurveName;
							if (TotalCount == 1)
							{
								FinalCurveName = CurveName;
							}
							else
							{
								FinalCurveName = CurveName + "_" + ChannelName;
							}

							FFormatNamedArguments Args;
							Args.Add(TEXT("CurveName"), FText::FromString(FinalCurveName));
							const FText StatusUpate = FText::Format(LOCTEXT("ImportingCustomAttributeCurvesDetail", "Importing Custom Attribute [{CurveName}]"), Args);
							GWarn->StatusUpdate(CurLinkIndex + 1, TotalLinks, StatusUpate);

							ImportCurveToAnimSequence(DestSeq, FinalCurveName, AnimCurve,  ACF_DefaultCurve, AnimTimeSpan);
						}
											
					}
				}

				Property = Node->GetNextProperty(Property); 
			}

			CurLinkIndex++;
		}

		GWarn->EndSlowTask();
	}

	// importing custom attribute END

	const bool bSourceDataExists = (DestSeq->SourceRawAnimationData.Num() > 0);
	TArray<AnimationTransformDebug::FAnimationTransformDebugData> TransformDebugData;
	int32 TotalNumKeys = 0;
	const FReferenceSkeleton& RefSkeleton = Skeleton->GetReferenceSkeleton();

	// import animation
	{
		GWarn->BeginSlowTask( LOCTEXT("BeginImportAnimation", "Importing Animation"), true);

		TArray<struct FRawAnimSequenceTrack>& RawAnimationData = bSourceDataExists? DestSeq->SourceRawAnimationData : DestSeq->RawAnimationData;
		DestSeq->TrackToSkeletonMapTable.Empty();
		DestSeq->AnimationTrackNames.Empty();
		RawAnimationData.Empty();

		TArray<FName> FbxRawBoneNames;
		FillAndVerifyBoneNames(Skeleton, SortedLinks, FbxRawBoneNames, FileName);

		UnFbx::FFbxImporter* FbxImporter = UnFbx::FFbxImporter::GetInstance();

		const bool bPreserveLocalTransform = FbxImporter->GetImportOptions()->bPreserveLocalTransform;

		// Build additional transform matrix
		UFbxAnimSequenceImportData* TemplateData = Cast<UFbxAnimSequenceImportData>(DestSeq->AssetImportData);
		FbxAMatrix FbxAddedMatrix;
		BuildFbxMatrixForImportTransform(FbxAddedMatrix, TemplateData);
		FMatrix AddedMatrix = Converter.ConvertMatrix(FbxAddedMatrix);

		const int32 NumSamplingKeys = FMath::FloorToInt(AnimTimeSpan.GetDuration().GetSecondDouble() * ResampleRate);
		const FbxTime TimeIncrement = (NumSamplingKeys > 1)? AnimTimeSpan.GetDuration() / (NumSamplingKeys - 1) : AnimTimeSpan.GetDuration();
		for(int32 SourceTrackIdx = 0; SourceTrackIdx < FbxRawBoneNames.Num(); ++SourceTrackIdx)
		{
			int32 NumKeysForTrack = 0;

			// see if it's found in Skeleton
			FName BoneName = FbxRawBoneNames[SourceTrackIdx];
			int32 BoneTreeIndex = RefSkeleton.FindBoneIndex(BoneName);

			// update status
			FFormatNamedArguments Args;
			Args.Add(TEXT("TrackName"), FText::FromName(BoneName));
			Args.Add(TEXT("TotalKey"), FText::AsNumber(NumSamplingKeys));
			Args.Add(TEXT("TrackIndex"), FText::AsNumber(SourceTrackIdx+1));
			Args.Add(TEXT("TotalTracks"), FText::AsNumber(FbxRawBoneNames.Num()));
			const FText StatusUpate = FText::Format(LOCTEXT("ImportingAnimTrackDetail", "Importing Animation Track [{TrackName}] ({TrackIndex}/{TotalTracks}) - TotalKey {TotalKey}"), Args);
			GWarn->StatusForceUpdate(SourceTrackIdx + 1, FbxRawBoneNames.Num(), StatusUpate);

			if (BoneTreeIndex!=INDEX_NONE)
			{
				bool bSuccess = true;

				FRawAnimSequenceTrack RawTrack;
				RawTrack.PosKeys.Empty();
				RawTrack.RotKeys.Empty();
				RawTrack.ScaleKeys.Empty();

				AnimationTransformDebug::FAnimationTransformDebugData NewDebugData;

				FbxNode* Link = SortedLinks[SourceTrackIdx];
				FbxNode * LinkParent = Link->GetParent();
			
				for(FbxTime CurTime = AnimTimeSpan.GetStart(); CurTime <= AnimTimeSpan.GetStop(); CurTime += TimeIncrement)
				{
					// save global trasnform
					FbxAMatrix GlobalMatrix = Link->EvaluateGlobalTransform(CurTime);
					// we'd like to verify this before going to Transform. 
					// currently transform has tons of NaN check, so it will crash there
					FMatrix GlobalUEMatrix = Converter.ConvertMatrix(GlobalMatrix);
					if (GlobalUEMatrix.ContainsNaN())
					{
						bSuccess = false;
						AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, FText::Format(LOCTEXT("Error_InvalidTransform",
							"Track {0} contains invalid transform. Could not import the track."), FText::FromName(BoneName))), FFbxErrors::Animation_TransformError);
						break;
					}

					FTransform GlobalTransform =  Converter.ConvertTransform(GlobalMatrix);
					if (GlobalTransform.ContainsNaN())
					{
						bSuccess = false;
						AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, FText::Format(LOCTEXT("Error_InvalidUnrealTransform",
											"Track {0} did not yeild valid transform. Please report this to animation team."), FText::FromName(BoneName))), FFbxErrors::Animation_TransformError);
						break;
					}

					// debug data, including import transformation
					FTransform AddedTransform(AddedMatrix);
					NewDebugData.SourceGlobalTransform.Add(GlobalTransform * AddedTransform);

					FTransform LocalTransform;
					if( !bPreserveLocalTransform && LinkParent)
					{
						// I can't rely on LocalMatrix. I need to recalculate quaternion/scale based on global transform if Parent exists
						FbxAMatrix ParentGlobalMatrix = Link->GetParent()->EvaluateGlobalTransform(CurTime);
						FTransform ParentGlobalTransform =  Converter.ConvertTransform(ParentGlobalMatrix);

						LocalTransform = GlobalTransform.GetRelativeTransform(ParentGlobalTransform);
						NewDebugData.SourceParentGlobalTransform.Add(ParentGlobalTransform);
					} 
					else
					{
						FbxAMatrix& LocalMatrix = Link->EvaluateLocalTransform(CurTime); 
						FbxVector4 NewLocalT = LocalMatrix.GetT();
						FbxVector4 NewLocalS = LocalMatrix.GetS();
						FbxQuaternion NewLocalQ = LocalMatrix.GetQ();

						LocalTransform.SetTranslation(Converter.ConvertPos(NewLocalT));
						LocalTransform.SetScale3D(Converter.ConvertScale(NewLocalS));
						LocalTransform.SetRotation(Converter.ConvertRotToQuat(NewLocalQ));

						NewDebugData.SourceParentGlobalTransform.Add(FTransform::Identity);
					}

					if(TemplateData && BoneTreeIndex == 0)
					{
						// If we found template data earlier, apply the import transform matrix to
						// the root track.
						LocalTransform.SetFromMatrix(LocalTransform.ToMatrixWithScale() * AddedMatrix);
					}

					if (LocalTransform.ContainsNaN())
					{
						bSuccess = false;
						AddTokenizedErrorMessage(FTokenizedMessage::Create(EMessageSeverity::Error, FText::Format(LOCTEXT("Error_InvalidUnrealLocalTransform",
											"Track {0} did not yeild valid local transform. Please report this to animation team."), FText::FromName(BoneName))), FFbxErrors::Animation_TransformError);
						break;
					}

					RawTrack.ScaleKeys.Add(LocalTransform.GetScale3D());
					RawTrack.PosKeys.Add(LocalTransform.GetTranslation());
					RawTrack.RotKeys.Add(LocalTransform.GetRotation());

					NewDebugData.RecalculatedLocalTransform.Add(LocalTransform);
					++NumKeysForTrack;
				}

				if (bSuccess)
				{
					//add new track
					int32 NewTrackIdx = RawAnimationData.Add(RawTrack);
					DestSeq->AnimationTrackNames.Add(BoneName);

					NewDebugData.SetTrackData(NewTrackIdx, BoneTreeIndex, BoneName);

					// add mapping to skeleton bone track
					DestSeq->TrackToSkeletonMapTable.Add(FTrackToSkeletonMap(BoneTreeIndex));
					TransformDebugData.Add(NewDebugData);
				}
			}

			TotalNumKeys = FMath::Max( TotalNumKeys, NumKeysForTrack );
		}

		DestSeq->NumFrames = TotalNumKeys;
		GWarn->EndSlowTask();
	}

	// compress animation
	{
		GWarn->BeginSlowTask( LOCTEXT("BeginCompressAnimation", "Compress Animation"), true);
		GWarn->StatusForceUpdate(1, 1, LOCTEXT("CompressAnimation", "Compressing Animation"));
		// if source data exists, you should bake it to Raw to apply
		if(bSourceDataExists)
		{
			DestSeq->BakeTrackCurvesToRawAnimation();
		}
		else
		{
			// otherwise just compress
			DestSeq->PostProcessSequence();
		}

		// run debug mode
		AnimationTransformDebug::OutputAnimationTransformDebugData(TransformDebugData, TotalNumKeys, RefSkeleton);
		GWarn->EndSlowTask();
	}

	return true;
}