void FAnimNode_AimOffsetLookAt::UpdateFromLookAtTarget(FPoseContext& LocalPoseContext)
{
    const FBoneContainer& RequiredBones = LocalPoseContext.Pose.GetBoneContainer();
    if (RequiredBones.GetSkeletalMeshAsset())
    {
        const USkeletalMeshSocket* Socket = RequiredBones.GetSkeletalMeshAsset()->FindSocket(SourceSocketName);
        if (Socket)
        {
            const FTransform SocketLocalTransform = Socket->GetSocketLocalTransform();

            FBoneReference SocketBoneReference;
            SocketBoneReference.BoneName = Socket->BoneName;
            SocketBoneReference.Initialize(RequiredBones);

            if (SocketBoneReference.IsValid(RequiredBones))
            {
                const FCompactPoseBoneIndex SocketBoneIndex = SocketBoneReference.GetCompactPoseIndex(RequiredBones);

                FCSPose<FCompactPose> GlobalPose;
                GlobalPose.InitPose(LocalPoseContext.Pose);

                USkeletalMeshComponent* Component = LocalPoseContext.AnimInstanceProxy->GetSkelMeshComponent();
                AActor* Actor = Component ? Component->GetOwner() : nullptr;

                if (Component && Actor &&  BlendSpace)
                {
                    const FTransform ActorTransform = Actor->GetTransform();

                    const FTransform BoneTransform = GlobalPose.GetComponentSpaceTransform(SocketBoneIndex);
                    const FTransform SocketWorldTransform = SocketLocalTransform * BoneTransform * Component->ComponentToWorld;

                    // Convert Target to Actor Space
                    const FTransform TargetWorldTransform(LookAtLocation);

                    const FVector DirectionToTarget = ActorTransform.InverseTransformVectorNoScale(TargetWorldTransform.GetLocation() - SocketWorldTransform.GetLocation()).GetSafeNormal();
                    const FVector CurrentDirection = ActorTransform.InverseTransformVectorNoScale(SocketWorldTransform.GetUnitAxis(EAxis::X));

                    const FVector AxisX = FVector::ForwardVector;
                    const FVector AxisY = FVector::RightVector;
                    const FVector AxisZ = FVector::UpVector;

                    const FVector2D CurrentCoords = FMath::GetAzimuthAndElevation(CurrentDirection, AxisX, AxisY, AxisZ);
                    const FVector2D TargetCoords = FMath::GetAzimuthAndElevation(DirectionToTarget, AxisX, AxisY, AxisZ);
                    const FVector BlendInput(
                        FRotator::NormalizeAxis(FMath::RadiansToDegrees(TargetCoords.X - CurrentCoords.X)),
                        FRotator::NormalizeAxis(FMath::RadiansToDegrees(TargetCoords.Y - CurrentCoords.Y)),
                        0.f);

                    // Set X and Y, so ticking next frame is based on correct weights.
                    X = BlendInput.X;
                    Y = BlendInput.Y;

                    // Generate BlendSampleDataCache from inputs.
                    BlendSpace->GetSamplesFromBlendInput(BlendInput, BlendSampleDataCache);

                    if (CVarAimOffsetLookAtDebug.GetValueOnAnyThread() == 1)
                    {
                        DrawDebugLine(Component->GetWorld(), SocketWorldTransform.GetLocation(), TargetWorldTransform.GetLocation(), FColor::Green);
                        DrawDebugLine(Component->GetWorld(), SocketWorldTransform.GetLocation(), SocketWorldTransform.GetLocation() + SocketWorldTransform.GetUnitAxis(EAxis::X) * (TargetWorldTransform.GetLocation() - SocketWorldTransform.GetLocation()).Size(), FColor::Red);
                        DrawDebugCoordinateSystem(Component->GetWorld(), ActorTransform.GetLocation(), ActorTransform.GetRotation().Rotator(), 100.f);

                        FString DebugString = FString::Printf(TEXT("Socket (X:%f, Y:%f), Target (X:%f, Y:%f), Result (X:%f, Y:%f)")
                                                              , FMath::RadiansToDegrees(CurrentCoords.X)
                                                              , FMath::RadiansToDegrees(CurrentCoords.Y)
                                                              , FMath::RadiansToDegrees(TargetCoords.X)
                                                              , FMath::RadiansToDegrees(TargetCoords.Y)
                                                              , BlendInput.X
                                                              , BlendInput.Y);
                        GEngine->AddOnScreenDebugMessage(INDEX_NONE, 0.f, FColor::Red, DebugString, false);
                    }
                }
            }
        }
    }
}
void UDebugSkelMeshComponent::RefreshBoneTransforms(FActorComponentTickFunction* TickFunction)
{
	// Run regular update first so we get RequiredBones up to date.
	Super::RefreshBoneTransforms(NULL); // Pass NULL so we force non threaded work

	const bool bIsPreviewInstance = (PreviewInstance && PreviewInstance == AnimScriptInstance);

	BakedAnimationPoses.Empty();
	if(bDisplayBakedAnimation && bIsPreviewInstance && PreviewInstance->RequiredBones.IsValid())
	{
		if(UAnimSequence* Sequence = Cast<UAnimSequence>(PreviewInstance->CurrentAsset))
		{
			BakedAnimationPoses.AddUninitialized(PreviewInstance->RequiredBones.GetNumBones());
			bool bSavedUseSourceData = AnimScriptInstance->RequiredBones.ShouldUseSourceData();
			AnimScriptInstance->RequiredBones.SetUseRAWData(true);
			AnimScriptInstance->RequiredBones.SetUseSourceData(false);
			PreviewInstance->EnableControllers(false);
			GenSpaceBases(BakedAnimationPoses);
			AnimScriptInstance->RequiredBones.SetUseRAWData(false);
			AnimScriptInstance->RequiredBones.SetUseSourceData(bSavedUseSourceData);
			PreviewInstance->EnableControllers(true);
		}
	}

	SourceAnimationPoses.Empty();
	if(bDisplaySourceAnimation && bIsPreviewInstance && PreviewInstance->RequiredBones.IsValid())
	{
		if(UAnimSequence* Sequence = Cast<UAnimSequence>(PreviewInstance->CurrentAsset))
		{
			SourceAnimationPoses.AddUninitialized(PreviewInstance->RequiredBones.GetNumBones());
			bool bSavedUseSourceData = AnimScriptInstance->RequiredBones.ShouldUseSourceData();
			AnimScriptInstance->RequiredBones.SetUseSourceData(true);
			PreviewInstance->EnableControllers(false);
			GenSpaceBases(SourceAnimationPoses);
			AnimScriptInstance->RequiredBones.SetUseSourceData(bSavedUseSourceData);
			PreviewInstance->EnableControllers(true);
		}
	}

	UncompressedSpaceBases.Empty();
	if (bDisplayRawAnimation && AnimScriptInstance && AnimScriptInstance->RequiredBones.IsValid())
	{
		UncompressedSpaceBases.AddUninitialized(AnimScriptInstance->RequiredBones.GetNumBones());

		AnimScriptInstance->RequiredBones.SetUseRAWData(true);
		GenSpaceBases(UncompressedSpaceBases);
		AnimScriptInstance->RequiredBones.SetUseRAWData(false);
	}

	// Non retargeted pose.
	NonRetargetedSpaceBases.Empty();
	if( bDisplayNonRetargetedPose && AnimScriptInstance && AnimScriptInstance->RequiredBones.IsValid() )
	{
		NonRetargetedSpaceBases.AddUninitialized(AnimScriptInstance->RequiredBones.GetNumBones());
		AnimScriptInstance->RequiredBones.SetDisableRetargeting(true);
		GenSpaceBases(NonRetargetedSpaceBases);
		AnimScriptInstance->RequiredBones.SetDisableRetargeting(false);
	}

	// Only works in PreviewInstance, and not for anim blueprint. This is intended.
	AdditiveBasePoses.Empty();
	if( bDisplayAdditiveBasePose && bIsPreviewInstance && PreviewInstance->RequiredBones.IsValid() )
	{
		if (UAnimSequence* Sequence = Cast<UAnimSequence>(PreviewInstance->CurrentAsset)) 
		{ 
			if (Sequence->IsValidAdditive()) 
			{ 
				FCSPose<FCompactPose> CSAdditiveBasePose;
				{
					FCompactPose AdditiveBasePose;
					FBlendedCurve AdditiveCurve(PreviewInstance);
					AdditiveBasePose.SetBoneContainer(&PreviewInstance->RequiredBones);
					Sequence->GetAdditiveBasePose(AdditiveBasePose, AdditiveCurve, FAnimExtractContext(PreviewInstance->CurrentTime));
					CSAdditiveBasePose.InitPose(AdditiveBasePose);
				}

				for (int32 i = 0; i < AdditiveBasePoses.Num(); ++i)
				{
					FCompactPoseBoneIndex CompactIndex = PreviewInstance->RequiredBones.MakeCompactPoseIndex(FMeshPoseBoneIndex(i));
					AdditiveBasePoses[i] = CSAdditiveBasePose.GetComponentSpaceTransform(CompactIndex);
				}
			}
		}
	}
}
Esempio n. 3
0
bool UAnimPreviewInstance::NativeEvaluateAnimation(FPoseContext& Output)
{
#if WITH_EDITORONLY_DATA
	if(bForceRetargetBasePose)
	{
		USkeletalMeshComponent* MeshComponent = GetSkelMeshComponent();
		if(MeshComponent && MeshComponent->SkeletalMesh)
		{
			FAnimationRuntime::FillWithRetargetBaseRefPose(Output.Pose, GetSkelMeshComponent()->SkeletalMesh);
		}
		else
		{
			// ideally we'll return just ref pose, but not sure if this will work with LODs
			Output.Pose.ResetToRefPose();
		}
	}
	else
#endif // #if WITH_EDITORONLY_DATA
	{
		Super::NativeEvaluateAnimation(Output);
	}

	if (bEnableControllers)
	{
		UDebugSkelMeshComponent* Component = Cast<UDebugSkelMeshComponent>(GetSkelMeshComponent());

		if(Component && CurrentSkeleton)
		{
			// update curve controllers
			UpdateCurveController();

			// create bone controllers from 
			if(BoneControllers.Num() > 0 || CurveBoneControllers.Num() > 0)
			{
				FCompactPose PreController, PostController;
				// if set key is true, we should save pre controller local space transform 
				// so that we can calculate the delta correctly
				if(bSetKey)
				{
					PreController = Output.Pose;
				}

				FCSPose<FCompactPose> OutMeshPose;
				OutMeshPose.InitPose(&RequiredBones);

				// apply curve data first
				ApplyBoneControllers(Component, CurveBoneControllers, OutMeshPose);

				// and now apply bone controllers data
				// it is possible they can be overlapping, but then bone controllers will overwrite
				ApplyBoneControllers(Component, BoneControllers, OutMeshPose);

				// convert back to local @todo check this
				OutMeshPose.ConvertToLocalPoses(Output.Pose);

				if(bSetKey)
				{
					// now we have post controller, and calculate delta now
					PostController = Output.Pose;
					SetKeyImplementation(PreController, PostController);
				}
			}
			// if any other bone is selected, still go for set key even if nothing changed
			else if(Component->BonesOfInterest.Num() > 0)
			{
				if(bSetKey)
				{
					// in this case, pose is same
					SetKeyImplementation(Output.Pose, Output.Pose);
				}
			}
		}

		// we should unset here, just in case somebody clicks the key when it's not valid
		if(bSetKey)
		{
			bSetKey = false;
		}
	}

	return true;
}