Example #1
0
void ACoverActor::DetermineMovementDirection(FVector& MovementDirection, FRotator& FacingDirection)
{
	FName NearbySocket = GetNearbySocket();
	
	AActor* Char = UGameplayStatics::GetPlayerCharacter(GetWorld(), 0);

	//Determine the movement and facing direction of the player, based on the described logic
	//The way that we're deciding the facing direction is similar to the way we've decided
	//the movement direction
	if (NearbySocket.IsEqual("ForwardSocket"))
	{
		MovementDirection = -GetActorRightVector();
		FacingDirection = GetActorRotation();
	}
	else if (NearbySocket.IsEqual("BackwardSocket"))
	{
		MovementDirection = GetActorRightVector();
		FacingDirection = GetActorRotation() + FRotator(0, 180, 0);
	}
	else if (NearbySocket.IsEqual("RightSocket"))
	{
		MovementDirection = GetActorForwardVector();
		FacingDirection = GetActorRotation() + FRotator(0, 90, 0);
	}
	else
	{
		MovementDirection = -GetActorForwardVector();
		FacingDirection = GetActorRotation() + FRotator(0, -90.f, 0);
	}
}
static double GetSecondsPerCycle( const FStatPacketArray& Frame )
{
	const FName SecondsPerCycleFName = FName(TEXT("//STATGROUP_Engine//STAT_SecondsPerCycle///Seconds$32$Per$32$Cycle///////STATCAT_Advanced////"));
	const FName SecondsPerCycleRawName = FStatConstants::RAW_SecondsPerCycle;
	double Result = 0;

	for( int32 PacketIndex = 0; PacketIndex < Frame.Packets.Num(); PacketIndex++ )
	{
		const FStatPacket& Packet = *Frame.Packets[PacketIndex];
		const FStatMessagesArray& Data = Packet.StatMessages;

		if( Packet.ThreadType == EThreadType::Game )
		{
			for( int32 Index = 0; Index < Data.Num(); Index++ )
			{
				const FStatMessage& Item = Data[Index];
				check( Item.NameAndInfo.GetFlag( EStatMetaFlags::DummyAlwaysOne ) ); 

				const FName LongName = Item.NameAndInfo.GetEncodedName();
				const FName RawName = Item.NameAndInfo.GetRawName();
				if( LongName.IsEqual( SecondsPerCycleFName, ENameCase::IgnoreCase, false ) )
				{
					Result = Item.GetValue_double();
					UE_LOG( LogStats, Log, TEXT( "STAT_SecondsPerCycle is %f [ns]" ), Result*1000*1000 );

					PacketIndex = Frame.Packets.Num();
					break;
				}
			}	
		}
			
	}
	return Result;
}
void USceneCaptureComponent::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	const FName Name = (PropertyChangedEvent.Property != nullptr) ? PropertyChangedEvent.Property->GetFName() : NAME_None;
	const FName MemberPropertyName = (PropertyChangedEvent.MemberProperty != NULL) ? PropertyChangedEvent.MemberProperty->GetFName() : NAME_None;

	// If our ShowFlagSetting UStruct changed, (or if PostEditChange was called without specifying a property) update the actual show flags
	if (MemberPropertyName.IsEqual("ShowFlagSettings") || MemberPropertyName.IsNone())
	{
		UpdateShowFlags();
	}
}
void FAnimNode_MMDIK::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer& RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{

	FVector EffectorLocation(FVector::ZeroVector);
	FVector JointTargetLocation(FVector::ZeroVector);
	TEnumAsByte<enum EBoneControlSpace> EffectorLocationSpace(BCS_BoneSpace);
	TEnumAsByte<enum EBoneControlSpace> JointTargetLocationSpace(BCS_ParentBoneSpace);

	FTransform UpperLimbCSTransform;
	FTransform LowerLimbCSTransform;
	FTransform EndBoneCSTransform;
	FTransform JointTargetTransform;
	const float BlendWeight = FMath::Clamp<float>(1.0f, 0.f, 1.f);

	check(OutBoneTransforms.Num() == 0);

	const FStringAssetReference& AssetRef = MMDExtendAssetRef.ToStringReference();

	UMMDExtendAsset* MMDExtendAssetPtr = MMDExtendAssetRef.Get();

	if (MMDExtendAssetPtr == nullptr)
	{
		UE_LOG(LogAnimation, Warning, TEXT("FAnimNode_MMDIK::EvaluateBoneTransforms: MMExtendPtr is nullptr!"));
		return;
	}

	for (int32 indexIK = 0; indexIK < MMDExtendAssetPtr->IkInfoList.Num(); indexIK++)
	{
		JointTargetLocationSpace = BCS_ParentBoneSpace;

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

		// IKBoneIndex
		const FName EffectorSpaceBoneName = MMDExtendAssetPtr->IkInfoList[indexIK].IKBoneName;
		const int32 EffectorSpaceBoneIndex = MMDExtendAssetPtr->IkInfoList[indexIK].IKBoneIndex;

		const FName EndBoneName = MMDExtendAssetPtr->IkInfoList[indexIK].TargetBoneName;
		const int32 EndBoneIndex = MMDExtendAssetPtr->IkInfoList[indexIK].TargetBoneIndex;

		if (EffectorSpaceBoneName.IsEqual(TEXT("左つま先IK")) || EffectorSpaceBoneName.IsEqual(TEXT("右つま先IK")))
		{
			JointTargetLocationSpace = BCS_BoneSpace;
		}

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

		int32 UpperLimbIndex = INDEX_NONE;

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

		}

		if (!bInvalidLimb)
		{
			int32 JointTargetSpaceBoneIndex = INDEX_NONE;

			if (MMDExtendAssetPtr->IkInfoList[indexIK].ikLinkList.Num() > 0)
			{
				JointTargetSpaceBoneIndex = MMDExtendAssetPtr->IkInfoList[indexIK].ikLinkList[0].BoneIndex;
			}

			UpperLimbCSTransform = MeshBases.GetComponentSpaceTransform(UpperLimbIndex);
			LowerLimbCSTransform = MeshBases.GetComponentSpaceTransform(LowerLimbIndex);

			EndBoneCSTransform = MeshBases.GetComponentSpaceTransform(EndBoneIndex);

			FTransform JointTargetTransform(JointTargetLocation);
			FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, JointTargetTransform, JointTargetSpaceBoneIndex, JointTargetLocationSpace);

			const FVector RootPos = UpperLimbCSTransform.GetTranslation();
			const FVector InitialJointPos = LowerLimbCSTransform.GetTranslation();
			const FVector InitialEndPos = EndBoneCSTransform.GetTranslation();

			FTransform EffectorTransform(EffectorLocation);
			FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, EffectorTransform, EffectorSpaceBoneIndex, EffectorLocationSpace);

			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;
			}

			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;

			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).GetSafeNormal();
				FVector const NewDir = (OutJointPos - RootPos).GetSafeNormal();
				// 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).GetSafeNormal();
				FVector const NewDir = (OutEndPos - OutJointPos).GetSafeNormal();

				// 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.
			{

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

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

			OutBoneTransforms.Sort([](const FBoneTransform& A, const FBoneTransform& B)
			{
				return A.BoneIndex < B.BoneIndex;
			});

			if (OutBoneTransforms.Num() > 0)
			{
				MeshBases.LocalBlendCSBoneTransforms(OutBoneTransforms, BlendWeight);
				OutBoneTransforms.Empty();
			}

		}

	}

}