void UAnimCompress_RemoveLinearKeys::ProcessAnimationTracks(
	UAnimSequence* AnimSeq, 
	const TArray<FBoneData>& BoneData, 
	TArray<FTranslationTrack>& PositionTracks,
	TArray<FRotationTrack>& RotationTracks, 
	TArray<FScaleTrack>& ScaleTracks)
{
	// extract all the data we'll need about the skeleton and animation sequence
	const int32 NumBones			= BoneData.Num();
	const int32 NumFrames			= AnimSeq->NumFrames;
	const float SequenceLength	= AnimSeq->SequenceLength;
	const int32 LastFrame = NumFrames-1;
	const float FrameRate = (float)(LastFrame) / SequenceLength;
	const float TimePerFrame = SequenceLength / (float)(LastFrame);

	const TArray<FTransform>& RefPose = AnimSeq->GetSkeleton()->GetRefLocalPoses();
	const bool bHasScale =  (ScaleTracks.Num() > 0);

	// make sure the parent key scale is properly bound to 1.0 or more
	ParentKeyScale = FMath::Max(ParentKeyScale, 1.0f);

	// generate the raw and compressed skeleton in world-space
	TArray<FTransform> RawWorldBones;
	TArray<FTransform> NewWorldBones;
	RawWorldBones.Empty(NumBones * NumFrames);
	NewWorldBones.Empty(NumBones * NumFrames);
	RawWorldBones.AddZeroed(NumBones * NumFrames);
	NewWorldBones.AddZeroed(NumBones * NumFrames);

	// generate an array to hold the indices of our end effectors
	TArray<int32> EndEffectors;
	EndEffectors.Empty(NumBones);

	// Create an array of FTransform to use as a workspace
	TArray<FTransform> BoneAtoms;

	// setup the raw bone transformation and find all end effectors
	for ( int32 BoneIndex = 0; BoneIndex < NumBones; ++BoneIndex )
	{
		// get the raw world-atoms for this bone
		UpdateWorldBoneTransformTable(
			AnimSeq, 
			BoneData, 
			RefPose,
			BoneIndex,
			true,
			RawWorldBones);

		// also record all end-effectors we find
		const FBoneData& Bone = BoneData[BoneIndex];
		if (Bone.IsEndEffector())
		{
			EndEffectors.Add(BoneIndex);
		}
	}

	TArray<int32> TargetBoneIndices;
	// for each bone...
	for ( int32 BoneIndex = 0; BoneIndex < NumBones; ++BoneIndex )
	{
		const FBoneData& Bone = BoneData[BoneIndex];
		const int32 ParentBoneIndex = Bone.GetParent();

		const int32 TrackIndex = AnimSeq->GetSkeleton()->GetAnimationTrackIndex(BoneIndex, AnimSeq, true);

		if (TrackIndex != INDEX_NONE)
		{
			// get the tracks we will be editing for this bone
			FRotationTrack& RotTrack = RotationTracks[TrackIndex];
			FTranslationTrack& TransTrack = PositionTracks[TrackIndex];
			const int32 NumRotKeys = RotTrack.RotKeys.Num();
			const int32 NumPosKeys = TransTrack.PosKeys.Num();
			const int32 NumScaleKeys = (bHasScale)? ScaleTracks[TrackIndex].ScaleKeys.Num() : 0;

			check( (NumPosKeys == 1) || (NumRotKeys == 1) || (NumPosKeys == NumRotKeys) );

			// build an array of end effectors we need to monitor
			TargetBoneIndices.Reset(NumBones);

			int32 HighestTargetBoneIndex = BoneIndex;
			int32 FurthestTargetBoneIndex = BoneIndex;
			int32 ShortestChain = 0;
			float OffsetLength= -1.0f;
			for (int32 EffectorIndex=0; EffectorIndex < EndEffectors.Num(); ++EffectorIndex)
			{
				const int32 EffectorBoneIndex = EndEffectors[EffectorIndex];
				const FBoneData& EffectorBoneData = BoneData[EffectorBoneIndex];

				int32 RootIndex = EffectorBoneData.BonesToRoot.Find(BoneIndex);
				if (RootIndex != INDEX_NONE)
				{
					if (ShortestChain == 0 || (RootIndex+1) < ShortestChain)
					{
						ShortestChain = (RootIndex+1);
					}
					TargetBoneIndices.Add(EffectorBoneIndex);
					HighestTargetBoneIndex = FMath::Max(HighestTargetBoneIndex, EffectorBoneIndex);
					float ChainLength= 0.0f;
					for (long FamilyIndex=0; FamilyIndex < RootIndex; ++FamilyIndex)
					{
						const int32 NextParentBoneIndex= EffectorBoneData.BonesToRoot[FamilyIndex];
						ChainLength += RefPose[NextParentBoneIndex].GetTranslation().Size();
					}

					if (ChainLength > OffsetLength)
					{
						FurthestTargetBoneIndex = EffectorBoneIndex;
						OffsetLength = ChainLength;
					}

				}
			}

			// if requested, retarget the FBoneAtoms towards the target end effectors
			if (bRetarget)
			{
				if (NumScaleKeys > 0 && ParentBoneIndex != INDEX_NONE)
				{
					// update our bone table from the current bone through the last end effector we need to test
					UpdateWorldBoneTransformRange(
						AnimSeq, 
						BoneData, 
						RefPose,
						PositionTracks,
						RotationTracks,
						ScaleTracks,
						BoneIndex,
						HighestTargetBoneIndex,
						false,
						NewWorldBones);

					FScaleTrack& ScaleTrack = ScaleTracks[TrackIndex];

					// adjust all translation keys to align better with the destination
					for ( int32 KeyIndex = 0; KeyIndex < NumScaleKeys; ++KeyIndex )
					{
						FVector& Key= ScaleTrack.ScaleKeys[KeyIndex];

						const int32 FrameIndex= FMath::Clamp(KeyIndex, 0, LastFrame);
						const FTransform& NewWorldParent = NewWorldBones[(ParentBoneIndex*NumFrames) + FrameIndex];
						const FTransform& RawWorldChild = RawWorldBones[(BoneIndex*NumFrames) + FrameIndex];
						const FTransform& RelTM = (RawWorldChild.GetRelativeTransform(NewWorldParent));
						const FTransform Delta = FTransform(RelTM);

						Key = Delta.GetScale3D();
					}
				}
							
				if (NumRotKeys > 0 && ParentBoneIndex != INDEX_NONE)
				{
					if (HighestTargetBoneIndex == BoneIndex)
					{
						for ( int32 KeyIndex = 0; KeyIndex < NumRotKeys; ++KeyIndex )
						{
							FQuat& Key = RotTrack.RotKeys[KeyIndex];

							check(ParentBoneIndex != INDEX_NONE);
							const int32 FrameIndex = FMath::Clamp(KeyIndex, 0, LastFrame);
							FTransform NewWorldParent = NewWorldBones[(ParentBoneIndex*NumFrames) + FrameIndex];
							FTransform RawWorldChild = RawWorldBones[(BoneIndex*NumFrames) + FrameIndex];
							const FTransform& RelTM = (RawWorldChild.GetRelativeTransform(NewWorldParent)); 
							FQuat Rot = FTransform(RelTM).GetRotation();

							const FQuat& AlignedKey = EnforceShortestArc(Key, Rot);
							Key = AlignedKey;
						}
					}
					else
					{
						// update our bone table from the current bone through the last end effector we need to test
						UpdateWorldBoneTransformRange(
							AnimSeq, 
							BoneData, 
							RefPose,
							PositionTracks,
							RotationTracks,
							ScaleTracks,
							BoneIndex,
							HighestTargetBoneIndex,
							false,
							NewWorldBones);
						
						// adjust all rotation keys towards the end effector target
						for ( int32 KeyIndex = 0; KeyIndex < NumRotKeys; ++KeyIndex )
						{
							FQuat& Key = RotTrack.RotKeys[KeyIndex];

							const int32 FrameIndex = FMath::Clamp(KeyIndex, 0, LastFrame);

							const FTransform& NewWorldTransform = NewWorldBones[(BoneIndex*NumFrames) + FrameIndex];

							const FTransform& DesiredChildTransform = RawWorldBones[(FurthestTargetBoneIndex*NumFrames) + FrameIndex].GetRelativeTransform(NewWorldTransform);
							const FTransform& CurrentChildTransform = NewWorldBones[(FurthestTargetBoneIndex*NumFrames) + FrameIndex].GetRelativeTransform(NewWorldTransform);

							// find the two vectors which represent the angular error we are trying to correct
							const FVector& CurrentHeading = CurrentChildTransform.GetTranslation();
							const FVector& DesiredHeading = DesiredChildTransform.GetTranslation();

							// if these are valid, we can continue
							if (!CurrentHeading.IsNearlyZero() && !DesiredHeading.IsNearlyZero())
							{
								const float DotResult = CurrentHeading.GetSafeNormal() | DesiredHeading.GetSafeNormal();

								// limit the range we will retarget to something reasonable (~60 degrees)
								if (DotResult < 1.0f && DotResult > 0.5f)
								{
									FQuat Adjustment= FQuat::FindBetweenVectors(CurrentHeading, DesiredHeading);
									Adjustment= EnforceShortestArc(FQuat::Identity, Adjustment);

									const FVector Test = Adjustment.RotateVector(CurrentHeading);
									const float DeltaSqr = (Test - DesiredHeading).SizeSquared();
									if (DeltaSqr < FMath::Square(0.001f))
									{
										FQuat NewKey = Adjustment * Key;
										NewKey.Normalize();

										const FQuat& AlignedKey = EnforceShortestArc(Key, NewKey);
										Key = AlignedKey;
									}
								}
							}
						}
					}
				}

				if (NumPosKeys > 0 && ParentBoneIndex != INDEX_NONE)
				{
					// update our bone table from the current bone through the last end effector we need to test
					UpdateWorldBoneTransformRange(
						AnimSeq, 
						BoneData, 
						RefPose,
						PositionTracks,
						RotationTracks,
						ScaleTracks,
						BoneIndex,
						HighestTargetBoneIndex,
						false,
						NewWorldBones);

					// adjust all translation keys to align better with the destination
					for ( int32 KeyIndex = 0; KeyIndex < NumPosKeys; ++KeyIndex )
					{
						FVector& Key= TransTrack.PosKeys[KeyIndex];

						const int32 FrameIndex= FMath::Clamp(KeyIndex, 0, LastFrame);
						FTransform NewWorldParent = NewWorldBones[(ParentBoneIndex*NumFrames) + FrameIndex];
						FTransform RawWorldChild = RawWorldBones[(BoneIndex*NumFrames) + FrameIndex];
						const FTransform& RelTM = RawWorldChild.GetRelativeTransform(NewWorldParent);
						const FTransform Delta = FTransform(RelTM);
						ensure (!Delta.ContainsNaN());

						Key = Delta.GetTranslation();
					}
				}

			}

			// look for a parent track to reference as a guide
			int32 GuideTrackIndex = INDEX_NONE;
			if (ParentKeyScale > 1.0f)
			{
				for (long FamilyIndex=0; (FamilyIndex < Bone.BonesToRoot.Num()) && (GuideTrackIndex == INDEX_NONE); ++FamilyIndex)
				{
					const int32 NextParentBoneIndex= Bone.BonesToRoot[FamilyIndex];

					GuideTrackIndex = AnimSeq->GetSkeleton()->GetAnimationTrackIndex(NextParentBoneIndex, AnimSeq, true);
				}
			}

			// update our bone table from the current bone through the last end effector we need to test
			UpdateWorldBoneTransformRange(
				AnimSeq, 
				BoneData, 
				RefPose,
				PositionTracks,
				RotationTracks,
				ScaleTracks,
				BoneIndex,
				HighestTargetBoneIndex,
				false,
				NewWorldBones);

			// rebuild the BoneAtoms table using the current set of keys
			UpdateBoneAtomList(AnimSeq, BoneIndex, TrackIndex, NumFrames, TimePerFrame, BoneAtoms); 

			// determine the EndEffectorTolerance. 
			// We use the Maximum value by default, and the Minimum value
			// as we approach the end effectors
			float EndEffectorTolerance = MaxEffectorDiff;
			if (ShortestChain <= 1)
			{
				EndEffectorTolerance = MinEffectorDiff;
			}

			// Determine if a guidance track should be used to aid in choosing keys to retain
			TArray<float>* GuidanceTrack = NULL;
			float GuidanceScale = 1.0f;
			if (GuideTrackIndex != INDEX_NONE)
			{
				FTranslationTrack& GuideTransTrack = PositionTracks[GuideTrackIndex];
				GuidanceTrack = &GuideTransTrack.Times;
				GuidanceScale = ParentKeyScale;
			}
			
			// if the TargetBoneIndices array is empty, then this bone is an end effector.
			// so we add it to the list to maintain our tolerance checks
			if (TargetBoneIndices.Num() == 0)
			{
				TargetBoneIndices.Add(BoneIndex);
			}

			if (bActuallyFilterLinearKeys)
			{
				if (bHasScale)
				{
					FScaleTrack& ScaleTrack = ScaleTracks[TrackIndex];
					// filter out translations we can approximate through interpolation
					FilterLinearKeysTemplate<FVector>(
						ScaleTrack.ScaleKeys, 
						ScaleTrack.Times, 
						BoneAtoms,
						GuidanceTrack, 
						RawWorldBones,
						NewWorldBones,
						TargetBoneIndices,
						NumFrames,
						BoneIndex,
						ParentBoneIndex,
						GuidanceScale, 
						MaxScaleDiff, 
						EndEffectorTolerance,
						EffectorDiffSocket,
						BoneData);

					// update our bone table from the current bone through the last end effector we need to test
					UpdateWorldBoneTransformRange(
						AnimSeq, 
						BoneData, 
						RefPose,
						PositionTracks,
						RotationTracks,
						ScaleTracks,
						BoneIndex,
						HighestTargetBoneIndex,
						false,
						NewWorldBones);

					// rebuild the BoneAtoms table using the current set of keys
					UpdateBoneAtomList(AnimSeq, BoneIndex, TrackIndex, NumFrames, TimePerFrame, BoneAtoms); 
				}

				// filter out translations we can approximate through interpolation
				FilterLinearKeysTemplate<FVector>(
					TransTrack.PosKeys, 
					TransTrack.Times, 
					BoneAtoms,
					GuidanceTrack, 
					RawWorldBones,
					NewWorldBones,
					TargetBoneIndices,
					NumFrames,
					BoneIndex,
					ParentBoneIndex,
					GuidanceScale, 
					MaxPosDiff, 
					EndEffectorTolerance,
					EffectorDiffSocket,
					BoneData);

				// update our bone table from the current bone through the last end effector we need to test
				UpdateWorldBoneTransformRange(
					AnimSeq, 
					BoneData, 
					RefPose,
					PositionTracks,
					RotationTracks,
					ScaleTracks,
					BoneIndex,
					HighestTargetBoneIndex,
					false,
					NewWorldBones);

				// rebuild the BoneAtoms table using the current set of keys
				UpdateBoneAtomList(AnimSeq, BoneIndex, TrackIndex, NumFrames, TimePerFrame, BoneAtoms); 

				// filter out rotations we can approximate through interpolation
				FilterLinearKeysTemplate<FQuat>(
					RotTrack.RotKeys, 
					RotTrack.Times, 
					BoneAtoms,
					GuidanceTrack, 
					RawWorldBones,
					NewWorldBones,
					TargetBoneIndices,
					NumFrames,
					BoneIndex,
					ParentBoneIndex,
					GuidanceScale, 
					MaxAngleDiff, 
					EndEffectorTolerance,
					EffectorDiffSocket,
					BoneData);
			}
		}

		// make sure the final compressed keys are repesented in our NewWorldBones table
		UpdateWorldBoneTransformRange(
			AnimSeq, 
			BoneData, 
			RefPose,
			PositionTracks,
			RotationTracks,
			ScaleTracks,
			BoneIndex,
			BoneIndex,
			false,
			NewWorldBones);
	}
};
FTransform UpdateBoneAtom(int32 BoneIndex, const FTransform& Atom, const T& Component)
{
	// only the custom instantiations below are valid
	check(0);
	return FTransform();
}
Пример #3
0
void AGameplayPawn::AddSpriteAndUpdate(int x, int y)
{
	GroupedGroundSprite->AddInstance(FTransform(FRotator(0.0f, 0.0f, 90.0f), FVector(GridToWorldX(x)*SCALE_FACTOR, GridToWorldY(y)*SCALE_FACTOR, 0.0f), FVector(1.0f, 1.0f, 1.0f)),
		GroundSprite->GetSprite(), true, FColor::White);
}
AHierarchicalLODVolume* FHierarchicalLODUtilities::CreateVolumeForLODActor(ALODActor* InLODActor, UWorld* InWorld)
{
	FBox BoundingBox = InLODActor->GetComponentsBoundingBox(true);

	AHierarchicalLODVolume* Volume = InWorld->SpawnActor<AHierarchicalLODVolume>(AHierarchicalLODVolume::StaticClass(), FTransform(BoundingBox.GetCenter()));

	// this code builds a brush for the new actor
	Volume->PreEditChange(NULL);

	Volume->PolyFlags = 0;
	Volume->Brush = NewObject<UModel>(Volume, NAME_None, RF_Transactional);
	Volume->Brush->Initialize(nullptr, true);
	Volume->Brush->Polys = NewObject<UPolys>(Volume->Brush, NAME_None, RF_Transactional);
	Volume->GetBrushComponent()->Brush = Volume->Brush;
	Volume->BrushBuilder = NewObject<UCubeBuilder>(Volume, NAME_None, RF_Transactional);

	UCubeBuilder* CubeBuilder = static_cast<UCubeBuilder*>(Volume->BrushBuilder);

	CubeBuilder->X = BoundingBox.GetSize().X * 1.5f;
	CubeBuilder->Y = BoundingBox.GetSize().Y * 1.5f;
	CubeBuilder->Z = BoundingBox.GetSize().Z * 1.5f;

	Volume->BrushBuilder->Build(InWorld, Volume);

	FBSPOps::csgPrepMovingBrush(Volume);

	// Set the texture on all polys to NULL.  This stops invisible textures
	// dependencies from being formed on volumes.
	if (Volume->Brush)
	{
		for (int32 poly = 0; poly < Volume->Brush->Polys->Element.Num(); ++poly)
		{
			FPoly* Poly = &(Volume->Brush->Polys->Element[poly]);
			Poly->Material = NULL;
		}
	}

	Volume->PostEditChange();

	return Volume;
}
//=============================================================================
void UMotionControllerComponent::FViewExtension::PreRenderViewFamily_RenderThread(FRHICommandListImmediate& RHICmdList, FSceneViewFamily& InViewFamily)
{
	if (!MotionControllerComponent)
	{
		return;
	}
	FScopeLock ScopeLock(&CritSect);
	if (!MotionControllerComponent || MotionControllerComponent->bDisableLowLatencyUpdate || !CVarEnableMotionControllerLateUpdate.GetValueOnRenderThread())
	{
		return;
	}

	// Poll state for the most recent controller transform
	FVector Position;
	FRotator Orientation;
	if (!MotionControllerComponent->PollControllerState(Position, Orientation))
	{
		return;
	}
	
	if (LateUpdatePrimitives.Num())
	{
		// Calculate the late update transform that will rebase all children proxies within the frame of reference
		const FTransform OldLocalToWorldTransform = MotionControllerComponent->CalcNewComponentToWorld(MotionControllerComponent->GetRelativeTransform());
		const FTransform NewLocalToWorldTransform = MotionControllerComponent->CalcNewComponentToWorld(FTransform(Orientation, Position, MotionControllerComponent->GetComponentScale()));
		const FMatrix LateUpdateTransform = (OldLocalToWorldTransform.Inverse() * NewLocalToWorldTransform).ToMatrixWithScale();

		// Apply delta to the affected scene proxies
		for (auto PrimitiveInfo : LateUpdatePrimitives)
		{
			FPrimitiveSceneInfo* RetrievedSceneInfo = InViewFamily.Scene->GetPrimitiveSceneInfo(*PrimitiveInfo.IndexAddress);
			FPrimitiveSceneInfo* CachedSceneInfo = PrimitiveInfo.SceneInfo;
			// If the retrieved scene info is different than our cached scene info then the primitive was removed from the scene
			if (CachedSceneInfo == RetrievedSceneInfo && CachedSceneInfo->Proxy)
			{
				CachedSceneInfo->Proxy->ApplyLateUpdateTransform(LateUpdateTransform);
			}
		}
		LateUpdatePrimitives.Reset();
	}
}
Пример #6
0
void ACityMapMeshHolder::AddInstance(ECityMapMeshTag Tag, uint32 X, uint32 Y)
{
  AddInstance(Tag, FTransform(GetTileLocation(X, Y)));
}
Пример #7
0
bool UWorld::ComponentSweepSingle(struct FHitResult& OutHit,class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FRotator& Rot, const struct FComponentQueryParams& Params) const
{
	OutHit.TraceStart = Start;
	OutHit.TraceEnd = End;

	if(GetPhysicsScene() == NULL)
	{
		return false;
	}

	if(PrimComp == NULL)
	{
		UE_LOG(LogCollision, Log, TEXT("ComponentSweepSingle : No PrimComp"));
		return false;
	}

	// if target is skeletalmeshcomponent and do not support singlebody physics
	if ( !PrimComp->ShouldTrackOverlaps() )
	{
		UE_LOG(LogCollision, Log, TEXT("ComponentSweepSingle : (%s) Does not support skeletalmesh with Physics Asset and destructibles."), *PrimComp->GetPathName());
		return false;
	}

	ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType();
#if WITH_PHYSX
	// if extent is 0, do line trace
	if (PrimComp->IsZeroExtent())
	{
		return RaycastSingle(this, OutHit, Start, End, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()));
	}

	PxRigidActor* PRigidActor = PrimComp->BodyInstance.GetPxRigidActor();
	if(PRigidActor == NULL)
	{
		UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) No physics data"), *PrimComp->GetPathName());
		return false;
	}

	// Get all the shapes from the actor
	TArray<PxShape*, TInlineAllocator<8>> PShapes;
	PShapes.AddZeroed(PRigidActor->getNbShapes());
	int32 NumShapes = PRigidActor->getShapes(PShapes.GetData(), PShapes.Num());

	// calculate the test global pose of the actor
	PxTransform PGlobalStartPose = U2PTransform(FTransform(Start));
	PxTransform PGlobalEndPose = U2PTransform(FTransform(End));

	bool bHaveBlockingHit = false;
	PxQuat PGeomRot = U2PQuat(Rot.Quaternion());

	// Iterate over each shape
	for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++)
	{
		PxShape* PShape = PShapes[ShapeIdx];
		check(PShape);

		// Calc shape global pose
		PxTransform PLocalShape = PShape->getLocalPose();
		PxTransform PShapeGlobalStartPose = PGlobalStartPose.transform(PLocalShape);
		PxTransform PShapeGlobalEndPose = PGlobalEndPose.transform(PLocalShape);
		// consider localshape rotation for shape rotation
		PxQuat PShapeRot = PGeomRot * PLocalShape.q;

		GET_GEOMETRY_FROM_SHAPE(PGeom, PShape);

		if(PGeom != NULL)
		{
			// @todo UE4, this might not be the best behavior. If we're looking for the most closest, this have to change to save the result, and find the closest one or 
			// any other options, right now if anything hits first, it will return
			if (GeomSweepSingle(this, *PGeom, PShapeRot, OutHit, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())))
			{
				bHaveBlockingHit = true;
				break;
			}
		}
	}

	return bHaveBlockingHit;
#endif //WITH_PHYSX
	return false;
}
Пример #8
0
void FAnimNode_Fabrik::EvaluateBoneTransforms(USkeletalMeshComponent* SkelComp, const FBoneContainer& RequiredBones, FA2CSPose& MeshBases, TArray<FBoneTransform>& OutBoneTransforms)
{
	// IsValidToEvaluate validated our inputs, we don't need to check pre-requisites again.
	int32 const RootIndex = RootBone.BoneIndex;

	// Update EffectorLocation if it is based off a bone position
	FTransform CSEffectorTransform = FTransform(EffectorTransform);
	FAnimationRuntime::ConvertBoneSpaceTransformToCS(SkelComp, MeshBases, CSEffectorTransform, EffectorTransformBone.BoneIndex, EffectorTransformSpace);
	FVector const CSEffectorLocation = CSEffectorTransform.GetLocation();

	// @fixme - we need better to draw widgets and debug information in editor.
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	if (bEnableDebugDraw)
	{
		// Show end effector position.
		DrawDebugBox(SkelComp->GetWorld(), CSEffectorLocation, FVector(Precision), FColor::Green, true, 0.1f);
		DrawDebugCoordinateSystem(SkelComp->GetWorld(), CSEffectorLocation, CSEffectorTransform.GetRotation().Rotator(), 5.f, true, 0.1f);
	}
#endif

	// Gather all bone indices between root and tip.
	TArray<int32> BoneIndices;
	{
		int32 BoneIndex = TipBone.BoneIndex;
		do 
		{
			BoneIndices.Insert(BoneIndex, 0);
			BoneIndex = RequiredBones.GetParentBoneIndex(BoneIndex);
		} while (BoneIndex != RootIndex);
		BoneIndices.Insert(BoneIndex, 0);
	}

	// Maximum length of skeleton segment at full extension
	float MaximumReach = 0;

	// Gather transforms
	int32 const NumTransforms = BoneIndices.Num();
	OutBoneTransforms.AddUninitialized(NumTransforms);

	// Gather chain links. These are non zero length bones.
	TArray<FABRIKChainLink> Chain;
	Chain.Reserve(NumTransforms);

	// Start with Root Bone
	{
		int32 const & RootBoneIndex = BoneIndices[0];
		FTransform const BoneCSTransform = MeshBases.GetComponentSpaceTransform(RootBoneIndex);
		OutBoneTransforms[0] = FBoneTransform(RootBoneIndex, BoneCSTransform);

		Chain.Add(FABRIKChainLink(BoneCSTransform.GetLocation(), 0.f, RootBoneIndex, 0));
	}

	// Go through remaining transforms
	for (int32 TransformIndex = 1; TransformIndex < NumTransforms; TransformIndex++)
	{
		int32 const & BoneIndex = BoneIndices[TransformIndex];

		FTransform const BoneCSTransform = MeshBases.GetComponentSpaceTransform(BoneIndex);
		FVector const BoneCSPosition = BoneCSTransform.GetLocation();
		OutBoneTransforms[TransformIndex] = FBoneTransform(BoneIndex, BoneCSTransform);

		// Calculate the combined length of this segment of skeleton
		float const BoneLength = FVector::Dist(BoneCSPosition, OutBoneTransforms[TransformIndex-1].Transform.GetLocation());

		if (!FMath::IsNearlyZero(BoneLength))
		{
			Chain.Add(FABRIKChainLink(BoneCSPosition, BoneLength, BoneIndex, TransformIndex));
			MaximumReach += BoneLength;
		}
		else
		{
			// Mark this transform as a zero length child of the last link.
			// It will inherit position and delta rotation from parent link.
			FABRIKChainLink & ParentLink = Chain[Chain.Num()-1];
			ParentLink.ChildZeroLengthTransformIndices.Add(TransformIndex);
		}
	}

	bool bBoneLocationUpdated = false;
	float const RootToTargetDist = FVector::Dist(Chain[0].Position, CSEffectorLocation);
	int32 const NumChainLinks = Chain.Num();

	// FABRIK algorithm - bone translation calculation
	// If the effector is further away than the distance from root to tip, simply move all bones in a line from root to effector location
	if (RootToTargetDist > MaximumReach)
	{
		for (int32 LinkIndex = 1; LinkIndex < NumChainLinks; LinkIndex++)
		{
			FABRIKChainLink const & ParentLink = Chain[LinkIndex - 1];
			FABRIKChainLink & CurrentLink = Chain[LinkIndex];
			CurrentLink.Position = ParentLink.Position + (CSEffectorLocation - ParentLink.Position).GetUnsafeNormal() * CurrentLink.Length;
		}
		bBoneLocationUpdated = true;
	}
	else // Effector is within reach, calculate bone translations to position tip at effector location
	{
		int32 const TipBoneLinkIndex = NumChainLinks - 1;

		// Check distance between tip location and effector location
		float Slop = FVector::Dist(Chain[TipBoneLinkIndex].Position, CSEffectorLocation);
		if (Slop > Precision)
		{
			// Set tip bone at end effector location.
			Chain[TipBoneLinkIndex].Position = CSEffectorLocation;

			int32 IterationCount = 0;
			while ((Slop > Precision) && (IterationCount++ < MaxIterations))
			{
				// "Forward Reaching" stage - adjust bones from end effector.
				for (int32 LinkIndex = TipBoneLinkIndex - 1; LinkIndex > 0; LinkIndex--)
				{
					FABRIKChainLink & CurrentLink = Chain[LinkIndex];
					FABRIKChainLink const & ChildLink = Chain[LinkIndex + 1];

					CurrentLink.Position = ChildLink.Position + (CurrentLink.Position - ChildLink.Position).GetUnsafeNormal() * ChildLink.Length;
				}

				// "Backward Reaching" stage - adjust bones from root.
				for (int32 LinkIndex = 1; LinkIndex < TipBoneLinkIndex; LinkIndex++)
				{
					FABRIKChainLink const & ParentLink = Chain[LinkIndex - 1];
					FABRIKChainLink & CurrentLink = Chain[LinkIndex];

					CurrentLink.Position = ParentLink.Position + (CurrentLink.Position - ParentLink.Position).GetUnsafeNormal() * CurrentLink.Length;
				}

				// Re-check distance between tip location and effector location
				// Since we're keeping tip on top of effector location, check with its parent bone.
				Slop = FMath::Abs(Chain[TipBoneLinkIndex].Length - FVector::Dist(Chain[TipBoneLinkIndex - 1].Position, CSEffectorLocation));
			}

			// Place tip bone based on how close we got to target.
			{
				FABRIKChainLink const & ParentLink = Chain[TipBoneLinkIndex - 1];
				FABRIKChainLink & CurrentLink = Chain[TipBoneLinkIndex];

				CurrentLink.Position = ParentLink.Position + (CurrentLink.Position - ParentLink.Position).GetUnsafeNormal() * CurrentLink.Length;
			}

			bBoneLocationUpdated = true;
		}
	}

	// If we moved some bones, update bone transforms.
	if (bBoneLocationUpdated)
	{
		// First step: update bone transform positions from chain links.
		for (int32 LinkIndex = 0; LinkIndex < NumChainLinks; LinkIndex++)
		{
			FABRIKChainLink const & ChainLink = Chain[LinkIndex];
			OutBoneTransforms[ChainLink.TransformIndex].Transform.SetTranslation(ChainLink.Position);

			// If there are any zero length children, update position of those
			int32 const NumChildren = ChainLink.ChildZeroLengthTransformIndices.Num();
			for (int32 ChildIndex = 0; ChildIndex < NumChildren; ChildIndex++)
			{
				OutBoneTransforms[ChainLink.ChildZeroLengthTransformIndices[ChildIndex]].Transform.SetTranslation(ChainLink.Position);
			}
		}

		// FABRIK algorithm - re-orientation of bone local axes after translation calculation
		for (int32 LinkIndex = 0; LinkIndex < NumChainLinks - 1; LinkIndex++)
		{
			FABRIKChainLink const & CurrentLink = Chain[LinkIndex];
			FABRIKChainLink const & ChildLink = Chain[LinkIndex + 1];

			// Calculate pre-translation vector between this bone and child
			FVector const OldDir = (GetCurrentLocation(MeshBases, ChildLink.BoneIndex) - GetCurrentLocation(MeshBases, CurrentLink.BoneIndex)).GetUnsafeNormal();

			// Get vector from the post-translation bone to it's child
			FVector const NewDir = (ChildLink.Position - CurrentLink.Position).GetUnsafeNormal();

			// Calculate axis of rotation from pre-translation vector to post-translation vector
			FVector const RotationAxis = FVector::CrossProduct(OldDir, NewDir).GetSafeNormal();
			float const RotationAngle = FMath::Acos(FVector::DotProduct(OldDir, NewDir));
			FQuat const DeltaRotation = FQuat(RotationAxis, RotationAngle);
			// We're going to multiply it, in order to not have to re-normalize the final quaternion, it has to be a unit quaternion.
			checkSlow(DeltaRotation.IsNormalized());

			// Calculate absolute rotation and set it
			FTransform& CurrentBoneTransform = OutBoneTransforms[CurrentLink.TransformIndex].Transform;
			CurrentBoneTransform.SetRotation(DeltaRotation * CurrentBoneTransform.GetRotation());

			// Update zero length children if any
			int32 const NumChildren = CurrentLink.ChildZeroLengthTransformIndices.Num();
			for (int32 ChildIndex = 0; ChildIndex < NumChildren; ChildIndex++)
			{
				FTransform& ChildBoneTransform = OutBoneTransforms[CurrentLink.ChildZeroLengthTransformIndices[ChildIndex]].Transform;
				ChildBoneTransform.SetRotation(DeltaRotation * ChildBoneTransform.GetRotation());
			}
		}
	}

	// Special handling for tip bone's rotation.
	int32 const TipBoneTransformIndex = OutBoneTransforms.Num() - 1;
	switch (EffectorRotationSource)
	{
	case BRS_KeepLocalSpaceRotation:
		OutBoneTransforms[TipBoneTransformIndex].Transform = MeshBases.GetLocalSpaceTransform(BoneIndices[TipBoneTransformIndex]) * OutBoneTransforms[TipBoneTransformIndex - 1].Transform;
		break;
	case BRS_CopyFromTarget:
		OutBoneTransforms[TipBoneTransformIndex].Transform.SetRotation(CSEffectorTransform.GetRotation());
		break;
	case BRS_KeepComponentSpaceRotation:
		// Don't change the orientation at all
		break;
	default:
		break;
	}
}
void FDebugRenderSceneProxy::GetDynamicMeshElements(const TArray<const FSceneView*>& Views, const FSceneViewFamily& ViewFamily, uint32 VisibilityMap, FMeshElementCollector& Collector) const 
{
	QUICK_SCOPE_CYCLE_COUNTER( STAT_DebugRenderSceneProxy_GetDynamicMeshElements );

	// Draw solid spheres
	struct FMaterialCache
	{
		FMaterialCache() : bUseFakeLight(false) {}

		FMaterialRenderProxy* operator[](FLinearColor Color)
		{
			FMaterialRenderProxy* MeshColor = NULL;
			const uint32 HashKey = GetTypeHash(Color);
			if (MeshColorInstances.Contains(HashKey))
			{
				MeshColor = *MeshColorInstances.Find(HashKey);
			}
			else
			{
				if (bUseFakeLight && SolidMeshMaterial.IsValid())
				{
					
					MeshColor = new(FMemStack::Get())  FColoredMaterialRenderProxy(
						SolidMeshMaterial->GetRenderProxy(false, false),
						Color,
						"GizmoColor"
						);
				}
				else
				{
					MeshColor = new(FMemStack::Get()) FColoredMaterialRenderProxy(GEngine->DebugMeshMaterial->GetRenderProxy(false, false), Color);
				}

				MeshColorInstances.Add(HashKey, MeshColor);
			}

			return MeshColor;
		}

		void UseFakeLight(bool UseLight, class UMaterial* InMaterial) { bUseFakeLight = UseLight; SolidMeshMaterial = InMaterial; }

		TMap<uint32, FMaterialRenderProxy*> MeshColorInstances;
		TWeakObjectPtr<class UMaterial> SolidMeshMaterial;
		bool bUseFakeLight;
	};

	FMaterialCache MaterialCache[2];
	MaterialCache[1].UseFakeLight(true, SolidMeshMaterial.Get());

	for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
	{
		if (VisibilityMap & (1 << ViewIndex))
		{
			const FSceneView* View = Views[ViewIndex];
			FPrimitiveDrawInterface* PDI = Collector.GetPDI(ViewIndex);

			// Draw Lines
			const int32 LinesNum = Lines.Num();
			PDI->AddReserveLines(SDPG_World, LinesNum, false, false);
			for (const auto& CurrentLine : Lines)
			{
				PDI->DrawLine(CurrentLine.Start, CurrentLine.End, CurrentLine.Color, SDPG_World, CurrentLine.Thickness, 0, CurrentLine.Thickness > 0);
			}

			// Draw Dashed Lines
			for(int32 DashIdx=0; DashIdx<DashedLines.Num(); DashIdx++)
			{
				const FDashedLine& Dash = DashedLines[DashIdx];

				DrawDashedLine(PDI, Dash.Start, Dash.End, Dash.Color, Dash.DashSize, SDPG_World);
			}

			// Draw Arrows
			const uint32 ArrowsNum = ArrowLines.Num();
			PDI->AddReserveLines(SDPG_World, 5 * ArrowsNum, false, false);
			for (const auto& CurrentArrow : ArrowLines)
			{
				DrawLineArrow(PDI, CurrentArrow.Start, CurrentArrow.End, CurrentArrow.Color, 8.0f);
			}

			// Draw Stars
			for(int32 StarIdx=0; StarIdx<Stars.Num(); StarIdx++)
			{
				const FWireStar& Star = Stars[StarIdx];

				DrawWireStar(PDI, Star.Position, Star.Size, Star.Color, SDPG_World);
			}

			// Draw Cylinders
			for(const auto& Cylinder : Cylinders)
			{
				if (DrawType == SolidAndWireMeshes || DrawType == WireMesh)
				{
					DrawWireCylinder(PDI, Cylinder.Base, FVector(1, 0, 0), FVector(0, 1, 0), FVector(0, 0, 1), Cylinder.Color, Cylinder.Radius, Cylinder.HalfHeight, (DrawType == SolidAndWireMeshes) ? 9 : 16, SDPG_World, DrawType == SolidAndWireMeshes ? 2 : 0, 0, true);
				}

				if (DrawType == SolidAndWireMeshes || DrawType == SolidMesh)
				{
					GetCylinderMesh(Cylinder.Base, FVector(1, 0, 0), FVector(0, 1, 0), FVector(0, 0, 1), Cylinder.Radius, Cylinder.HalfHeight, 16, MaterialCache[0][Cylinder.Color.WithAlpha(DrawAlpha)], SDPG_World, ViewIndex, Collector);
				}
			}

			// Draw Boxes
			for(const auto& Box :  Boxes)
			{
				if (DrawType == SolidAndWireMeshes || DrawType == WireMesh)
				{
					DrawWireBox(PDI, Box.Transform.ToMatrixWithScale(), Box.Box, Box.Color, SDPG_World, DrawType == SolidAndWireMeshes ? 2 : 0, 0, true);
				}
				if (DrawType == SolidAndWireMeshes || DrawType == SolidMesh)
				{
					GetBoxMesh(FTransform(Box.Box.GetCenter()).ToMatrixNoScale() * Box.Transform.ToMatrixWithScale(), Box.Box.GetExtent(), MaterialCache[0][Box.Color.WithAlpha(DrawAlpha)], SDPG_World, ViewIndex, Collector);
				}
			}

			// Draw Boxes
			TArray<FVector> Verts;
			for (auto& CurrentCone : Cones)
			{
				if (DrawType == SolidAndWireMeshes || DrawType == WireMesh)
				{
					DrawWireCone(PDI, Verts, CurrentCone.ConeToWorld, 1, CurrentCone.Angle2, (DrawType == SolidAndWireMeshes) ? 9 : 16, CurrentCone.Color, SDPG_World, DrawType == SolidAndWireMeshes ? 2 : 0, 0, true);
				}
				if (DrawType == SolidAndWireMeshes || DrawType == SolidMesh)
				{
					GetConeMesh(CurrentCone.ConeToWorld, CurrentCone.Angle1, CurrentCone.Angle2, 16, MaterialCache[0][CurrentCone.Color.WithAlpha(DrawAlpha)], SDPG_World, ViewIndex, Collector);
				}
			}

			for (auto It = Spheres.CreateConstIterator(); It; ++It)
			{
				if (PointInView(It->Location, View))
				{
					if (DrawType == SolidAndWireMeshes || DrawType == WireMesh)
					{
						DrawWireSphere(PDI, It->Location, It->Color.WithAlpha(255), It->Radius, 20, SDPG_World, DrawType == SolidAndWireMeshes ? 2 : 0, 0, true);
					}
					if (DrawType == SolidAndWireMeshes || DrawType == SolidMesh)
					{
						GetSphereMesh(It->Location, FVector(It->Radius), 20, 7, MaterialCache[0][It->Color.WithAlpha(DrawAlpha)], SDPG_World, false, ViewIndex, Collector);
					}
				}
			}

			for (auto It = Capsles.CreateConstIterator(); It; ++It)
			{
				if (PointInView(It->Location, View))
				{
					if (DrawType == SolidAndWireMeshes || DrawType == WireMesh)
					{
						const float HalfAxis = FMath::Max<float>(It->HalfHeight - It->Radius, 1.f);
						const FVector BottomEnd = It->Location + It->Radius * It->Z;
						const FVector TopEnd = BottomEnd + (2 * HalfAxis) * It->Z;
						const float CylinderHalfHeight = (TopEnd - BottomEnd).Size() * 0.5;
						const FVector CylinderLocation = BottomEnd + CylinderHalfHeight * It->Z;
						DrawWireCapsule(PDI, CylinderLocation, It->X, It->Y, It->Z, It->Color, It->Radius, It->HalfHeight, (DrawType == SolidAndWireMeshes) ? 9 : 16, SDPG_World, DrawType == SolidAndWireMeshes ? 2 : 0, 0, true);
					}
					if (DrawType == SolidAndWireMeshes || DrawType == SolidMesh)
					{
						GetCapsuleMesh(It->Location, It->X, It->Y, It->Z, It->Color, It->Radius, It->HalfHeight, 16, MaterialCache[0][It->Color.WithAlpha(DrawAlpha)], SDPG_World, false, ViewIndex, Collector);
					}
				}
			}

			for (const auto& Mesh : Meshes)
			{
				FDynamicMeshBuilder MeshBuilder;
				MeshBuilder.AddVertices(Mesh.Vertices);
				MeshBuilder.AddTriangles(Mesh.Indices);

				MeshBuilder.GetMesh(FMatrix::Identity, MaterialCache[Mesh.Color.A == 255 ? 1 : 0][Mesh.Color.WithAlpha(DrawAlpha)], SDPG_World, false, false, ViewIndex, Collector);
			}

		}
	}
}
Пример #10
0
bool UWorld::ComponentOverlapTest(class UPrimitiveComponent* PrimComp, const FVector& Pos, const FRotator& Rot, const struct FComponentQueryParams& Params) const
{
	if(GetPhysicsScene() == NULL)
	{
		return false;
	}

	if(PrimComp == NULL)
	{
		UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : No PrimComp"));
		return false;
	}

	// if target is skeletalmeshcomponent and do not support singlebody physics, we don't support this yet
	// talk to @JG, SP, LH
	if ( !PrimComp->ShouldTrackOverlaps() )
	{
		UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : (%s) Does not support skeletalmesh with Physics Asset and destructibles."), *PrimComp->GetPathName());
		return false;
	}
#if WITH_PHYSX
	ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType();

	PxRigidActor* PRigidActor = PrimComp->BodyInstance.GetPxRigidActor();
	if(PRigidActor == NULL)
	{
		UE_LOG(LogCollision, Log, TEXT("ComponentOverlapMulti : (%s) No physics data"), *PrimComp->GetPathName());
		return false;
	}

	// calculate the test global pose of the actor
	PxTransform PTestGlobalPose = U2PTransform(FTransform(Rot, Pos));

	// Get all the shapes from the actor
	TArray<PxShape*, TInlineAllocator<8>> PShapes;
	PShapes.AddZeroed(PRigidActor->getNbShapes());
	int32 NumShapes = PRigidActor->getShapes(PShapes.GetData(), PShapes.Num());

	// Iterate over each shape
	for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++)
	{
		PxShape* PShape = PShapes[ShapeIdx];
		check(PShape);
		// Calc shape global pose
		PxTransform PLocalPose = PShape->getLocalPose();
		PxTransform PShapeGlobalPose = PTestGlobalPose.transform(PLocalPose);

		GET_GEOMETRY_FROM_SHAPE(PGeom, PShape);

		if(PGeom != NULL)
		{
			if( GeomOverlapTest(this, *PGeom, PShapeGlobalPose, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())))
			{
				// in this test, it only matters true or false. 
				// if we found first true, we don't care next test anymore. 
				return true;
			}
		}
	}

#endif //WITH_PHYSX
	return false;
}
Пример #11
0
FTransform UKismetMathLibrary::MakeTransform(FVector Translation, FRotator Rotation, FVector Scale)
{
	return FTransform(Rotation,Translation,Scale);
}
Пример #12
0
FTransform UKismetMathLibrary::Conv_VectorToTransform(FVector InTranslation)
{
	return FTransform(InTranslation);
}
Пример #13
0
bool FEdMode::InputDelta(FEditorViewportClient* InViewportClient, FViewport* InViewport, FVector& InDrag, FRotator& InRot, FVector& InScale)
{
    if(UsesPropertyWidgets())
    {
        AActor* SelectedActor = GetFirstSelectedActorInstance();
        if(SelectedActor != NULL && InViewportClient->GetCurrentWidgetAxis() != EAxisList::None)
        {
            GEditor->NoteActorMovement();

            if (EditedPropertyName != TEXT(""))
            {
                FTransform LocalTM = FTransform::Identity;

                if(bEditedPropertyIsTransform)
                {
                    LocalTM = GetPropertyValueByName<FTransform>(SelectedActor, EditedPropertyName, EditedPropertyIndex);
                }
                else
                {
                    FVector LocalPos = GetPropertyValueByName<FVector>(SelectedActor, EditedPropertyName, EditedPropertyIndex);
                    LocalTM = FTransform(LocalPos);
                }

                // Get actor transform (actor to world)
                FTransform ActorTM = SelectedActor->ActorToWorld();
                // Calculate world transform
                FTransform WorldTM = LocalTM * ActorTM;
                // Calc delta specified by drag
                //FTransform DeltaTM(InRot.Quaternion(), InDrag);
                // Apply delta in world space
                WorldTM.SetTranslation(WorldTM.GetTranslation() + InDrag);
                WorldTM.SetRotation(InRot.Quaternion() * WorldTM.GetRotation());
                // Convert new world transform back into local space
                LocalTM = WorldTM.GetRelativeTransform(ActorTM);
                // Apply delta scale
                LocalTM.SetScale3D(LocalTM.GetScale3D() + InScale);

                SelectedActor->PreEditChange(NULL);

                if(bEditedPropertyIsTransform)
                {
                    SetPropertyValueByName<FTransform>(SelectedActor, EditedPropertyName, EditedPropertyIndex, LocalTM);
                }
                else
                {
                    SetPropertyValueByName<FVector>(SelectedActor, EditedPropertyName, EditedPropertyIndex, LocalTM.GetLocation());
                }

                SelectedActor->PostEditChange();

                return true;
            }
        }
    }

    if( GetCurrentTool() )
    {
        return GetCurrentTool()->InputDelta(InViewportClient,InViewport,InDrag,InRot,InScale);
    }

    return 0;
}
/** custom instantiation of UpdateBoneAtom for FVectors */
template <> FTransform UpdateBoneAtom<FVector>(int32 BoneIndex, const FTransform& Atom, const FVector& Component)
{
	return FTransform(Atom.GetRotation(), Component, FVector(1.0f));
}
Пример #15
0
bool UWorld::ComponentSweepMulti(TArray<struct FHitResult>& OutHits, class UPrimitiveComponent* PrimComp, const FVector& Start, const FVector& End, const FRotator& Rot, const struct FComponentQueryParams& Params) const
{
	if(GetPhysicsScene() == NULL)
	{
		return false;
	}

	if(PrimComp == NULL)
	{
		UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : No PrimComp"));
		return false;
	}

	// if target is skeletalmeshcomponent and do not support singlebody physics
	if ( !PrimComp->ShouldTrackOverlaps() )
	{
		UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) Does not support skeletalmesh with Physics Asset and destructibles."), *PrimComp->GetPathName());
		return false;
	}

	ECollisionChannel TraceChannel = PrimComp->GetCollisionObjectType();

#if WITH_PHYSX
	// if extent is 0, do line trace
	if (PrimComp->IsZeroExtent())
	{
		return RaycastMulti(this, OutHits, Start, End, TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels()));
	}

	PxRigidActor* PRigidActor = PrimComp->BodyInstance.GetPxRigidActor();
	if(PRigidActor == NULL)
	{
		UE_LOG(LogCollision, Log, TEXT("ComponentSweepMulti : (%s) No physics data"), *PrimComp->GetPathName());
		return false;
	}
	PxScene * const PScene = PRigidActor->getScene();

	OutHits.Empty();

	// Get all the shapes from the actor
	TArray<PxShape*, TInlineAllocator<8>> PShapes;
	{
		SCOPED_SCENE_READ_LOCK(PScene);
		PShapes.AddZeroed(PRigidActor->getNbShapes());
		PRigidActor->getShapes(PShapes.GetData(), PShapes.Num());
	}

	// calculate the test global pose of the actor
	PxTransform PGlobalStartPose = U2PTransform(FTransform(Start));
	PxTransform PGlobalEndPose = U2PTransform(FTransform(End));

	bool bHaveBlockingHit = false;
	PxQuat PGeomRot = U2PQuat(Rot.Quaternion());

	// Iterate over each shape
	SCENE_LOCK_READ(PScene);
	for(int32 ShapeIdx=0; ShapeIdx<PShapes.Num(); ShapeIdx++)
	{
		PxShape* PShape = PShapes[ShapeIdx];
		check(PShape);

		TArray<struct FHitResult> Hits;

		// Calc shape global pose
		PxTransform PLocalShape = PShape->getLocalPose();
		PxTransform PShapeGlobalStartPose = PGlobalStartPose.transform(PLocalShape);
		PxTransform PShapeGlobalEndPose = PGlobalEndPose.transform(PLocalShape);
		// consider localshape rotation for shape rotation
		PxQuat PShapeRot = PGeomRot * PLocalShape.q;

		GET_GEOMETRY_FROM_SHAPE(PGeom, PShape);

		if(PGeom != NULL)
		{
			SCENE_UNLOCK_READ(PScene);
			if (GeomSweepMulti(this, *PGeom, PShapeRot, Hits, P2UVector(PShapeGlobalStartPose.p), P2UVector(PShapeGlobalEndPose.p), TraceChannel, Params, FCollisionResponseParams(PrimComp->GetCollisionResponseToChannels())))
			{
				bHaveBlockingHit = true;
			}

			OutHits.Append(Hits);
			SCENE_LOCK_READ(PScene);
		}
	}
	SCENE_UNLOCK_READ(PScene);

	return bHaveBlockingHit;
#endif //WITH_PHYSX
	return false;
}
/** custom instantiation of UpdateBoneAtom for FQuat */
template <> FTransform UpdateBoneAtom<FQuat>(int32 BoneIndex, const FTransform& Atom, const FQuat& Component)
{
	return FTransform(Component, Atom.GetTranslation(), FVector(1.0f));
}
bool FInstancedStaticMeshSCSEditorCustomization::HandleViewportDrag(class USceneComponent* InSceneComponent, class USceneComponent* InComponentTemplate, const FVector& InDeltaTranslation, const FRotator& InDeltaRotation, const FVector& InDeltaScale, const FVector& InPivot)
{
	check(InSceneComponent->IsA(UInstancedStaticMeshComponent::StaticClass()));

	UInstancedStaticMeshComponent* InstancedStaticMeshComponentScene = CastChecked<UInstancedStaticMeshComponent>(InSceneComponent);
	UInstancedStaticMeshComponent* InstancedStaticMeshComponentTemplate = CastChecked<UInstancedStaticMeshComponent>(InComponentTemplate);

	// transform pivot into component's space
	const FVector LocalPivot = InstancedStaticMeshComponentScene->GetComponentToWorld().InverseTransformPosition(InPivot);

	// Ensure that selected instances are up-to-date
	ValidateSelectedInstances(InstancedStaticMeshComponentScene);

	bool bMovedInstance = false;
	check(InstancedStaticMeshComponentScene->SelectedInstances.Num() == InstancedStaticMeshComponentScene->PerInstanceSMData.Num());
	for(int32 InstanceIndex = 0; InstanceIndex < InstancedStaticMeshComponentScene->SelectedInstances.Num(); InstanceIndex++)
	{
		if (InstancedStaticMeshComponentScene->SelectedInstances[InstanceIndex] && InstancedStaticMeshComponentTemplate->PerInstanceSMData.IsValidIndex(InstanceIndex))
		{
			const FMatrix& MatrixScene = InstancedStaticMeshComponentScene->PerInstanceSMData[InstanceIndex].Transform;

			FVector Translation = MatrixScene.GetOrigin();
			FRotator Rotation = MatrixScene.Rotator();
			FVector Scale = MatrixScene.GetScaleVector();

			FVector NewTranslation = Translation;
			FRotator NewRotation = Rotation;
			FVector NewScale = Scale;

			if( !InDeltaRotation.IsZero() )
			{
				NewRotation = FRotator( InDeltaRotation.Quaternion() * Rotation.Quaternion() );

				NewTranslation -= LocalPivot;
				NewTranslation = FRotationMatrix( InDeltaRotation ).TransformPosition( NewTranslation );
				NewTranslation += LocalPivot;
			}

			NewTranslation += InDeltaTranslation;

			if( !InDeltaScale.IsNearlyZero() )
			{
				const FScaleMatrix ScaleMatrix( InDeltaScale );

				FVector DeltaScale3D = ScaleMatrix.TransformPosition( Scale );
				NewScale = Scale + DeltaScale3D;

				NewTranslation -= LocalPivot;
				NewTranslation += ScaleMatrix.TransformPosition( NewTranslation );
				NewTranslation += LocalPivot;
			}

			InstancedStaticMeshComponentScene->UpdateInstanceTransform(InstanceIndex, FTransform(NewRotation, NewTranslation, NewScale));
			InstancedStaticMeshComponentTemplate->UpdateInstanceTransform(InstanceIndex, FTransform(NewRotation, NewTranslation, NewScale));

			bMovedInstance = true;
		}
	}

	return bMovedInstance;
}
Пример #18
0
void FLevelUtils::ApplyLevelTransform( ULevel* Level, const FTransform& LevelTransform, bool bDoPostEditMove )
{
	bool bTransformActors =  !LevelTransform.Equals(FTransform::Identity);
	if (bTransformActors)
	{
		if (!LevelTransform.GetRotation().IsIdentity())
		{
			// If there is a rotation applied, then the relative precomputed bounds become invalid.
			Level->bTextureStreamingRotationChanged = true;
		}

		// Iterate over all actors in the level and transform them
		for( int32 ActorIndex=0; ActorIndex<Level->Actors.Num(); ActorIndex++ )
		{
			AActor* Actor = Level->Actors[ActorIndex];

			// Don't want to transform children they should stay relative to there parents.
			if( Actor && Actor->GetAttachParentActor() == NULL )
			{
				// Has to modify root component directly as GetActorPosition is incorrect this early
				USceneComponent *RootComponent = Actor->GetRootComponent();
				if (RootComponent)
				{
					RootComponent->SetRelativeLocationAndRotation( LevelTransform.TransformPosition(RootComponent->RelativeLocation), (FTransform(RootComponent->RelativeRotation) * LevelTransform).Rotator());
				}			
			}
		}

#if WITH_EDITOR
		if( bDoPostEditMove )
		{
			ApplyPostEditMove( Level );						
		}
#endif // WITH_EDITOR

		Level->OnApplyLevelTransform.Broadcast(LevelTransform);
	}
}
Пример #19
0
FTransform UAnimBone::GetTransform()
{
	return FTransform(FQuat(Orientation), Position, Scale);
}
Пример #20
0
/** 
 *	Function for adding a box collision primitive to the supplied collision geometry based on the mesh of the box.
 * 
 *	We keep a list of triangle normals found so far. For each normal direction,
 *	we should have 2 distances from the origin (2 parallel box faces). If the 
 *	mesh is a box, we should have 3 distinct normal directions, and 2 distances
 *	found for each. The difference between these distances should be the box
 *	dimensions. The 3 directions give us the key axes, and therefore the
 *	box transformation matrix. This shouldn't rely on any vertex-ordering on 
 *	the triangles (normals are compared +ve & -ve). It also shouldn't matter 
 *	about how many triangles make up each side (but it will take longer). 
 *	We get the centre of the box from the centre of its AABB.
 */
void AddBoxGeomFromTris( const TArray<FPoly>& Tris, FKAggregateGeom* AggGeom, const TCHAR* ObjName )
{
	TArray<FPlaneInfo> Planes;

	for(int32 i=0; i<Tris.Num(); i++)
	{
		bool bFoundPlane = false;
		for(int32 j=0; j<Planes.Num() && !bFoundPlane; j++)
		{
			// if this triangle plane is already known...
			if( AreParallel( Tris[i].Normal, Planes[j].Normal ) )
			{
				// Always use the same normal when comparing distances, to ensure consistent sign.
				float Dist = Tris[i].Vertices[0] | Planes[j].Normal;

				// we only have one distance, and its not that one, add it.
				if( Planes[j].DistCount == 1 && !AreEqual(Dist, Planes[j].PlaneDist[0]) )
				{
					Planes[j].PlaneDist[1] = Dist;
					Planes[j].DistCount = 2;
				}
				// if we have a second distance, and its not that either, something is wrong.
				else if( Planes[j].DistCount == 2 && !AreEqual(Dist, Planes[j].PlaneDist[1]) )
				{
					UE_LOG(LogStaticMeshEdit, Log, TEXT("AddBoxGeomFromTris (%s): Found more than 2 planes with different distances."), ObjName);
					return;
				}

				bFoundPlane = true;
			}
		}

		// If this triangle does not match an existing plane, add to list.
		if(!bFoundPlane)
		{
			check( Planes.Num() < Tris.Num() );

			FPlaneInfo NewPlane;
			NewPlane.Normal = Tris[i].Normal;
			NewPlane.DistCount = 1;
			NewPlane.PlaneDist[0] = Tris[i].Vertices[0] | NewPlane.Normal;
			
			Planes.Add(NewPlane);
		}
	}

	// Now we have our candidate planes, see if there are any problems

	// Wrong number of planes.
	if(Planes.Num() != 3)
	{
		UE_LOG(LogStaticMeshEdit, Log, TEXT("AddBoxGeomFromTris (%s): Not very box-like (need 3 sets of planes)."), ObjName);
		return;
	}

	// If we don't have 3 pairs, we can't carry on.
	if((Planes[0].DistCount != 2) || (Planes[1].DistCount != 2) || (Planes[2].DistCount != 2))
	{
		UE_LOG(LogStaticMeshEdit, Log, TEXT("AddBoxGeomFromTris (%s): Incomplete set of planes (need 2 per axis)."), ObjName);
		return;
	}

	FMatrix BoxTM = FMatrix::Identity;

	BoxTM.SetAxis(0, Planes[0].Normal);
	BoxTM.SetAxis(1, Planes[1].Normal);

	// ensure valid TM by cross-product
	FVector ZAxis = Planes[0].Normal ^ Planes[1].Normal;

	if( !AreParallel(ZAxis, Planes[2].Normal) )
	{
		UE_LOG(LogStaticMeshEdit, Log, TEXT("AddBoxGeomFromTris (%s): Box axes are not perpendicular."), ObjName);
		return;
	}

	BoxTM.SetAxis(2, ZAxis);

	// OBB centre == AABB centre.
	FBox Box(0);
	for(int32 i=0; i<Tris.Num(); i++)
	{
		Box += Tris[i].Vertices[0];
		Box += Tris[i].Vertices[1];
		Box += Tris[i].Vertices[2];
	}

	BoxTM.SetOrigin( Box.GetCenter() );

	// Allocate box in array
	FKBoxElem BoxElem;
	BoxElem.SetTransform( FTransform( BoxTM ) );	
	// distance between parallel planes is box edge lengths.
	BoxElem.X = FMath::Abs(Planes[0].PlaneDist[0] - Planes[0].PlaneDist[1]);
	BoxElem.Y = FMath::Abs(Planes[1].PlaneDist[0] - Planes[1].PlaneDist[1]);
	BoxElem.Z = FMath::Abs(Planes[2].PlaneDist[0] - Planes[2].PlaneDist[1]);
	AggGeom->BoxElems.Add(BoxElem);
}
bool FHierarchicalLODUtilities::BuildStaticMeshForLODActor(ALODActor* LODActor, UPackage* AssetsOuter, const FHierarchicalSimplification& LODSetup, const uint32 LODIndex)
{
	if (AssetsOuter && LODActor)
	{
		if (!LODActor->IsDirty())
		{
			return false;
		}

		const FScopedTransaction Transaction(LOCTEXT("UndoAction_BuildProxyMesh", "Building Proxy Mesh for Cluster"));
		LODActor->Modify();		

		// Delete actor assets before generating new ones
		FHierarchicalLODUtilities::DestroyClusterData(LODActor);	
		
		TArray<UStaticMeshComponent*> AllComponents;
		{
			FScopedSlowTask SlowTask(LODActor->SubActors.Num(), (LOCTEXT("HierarchicalLODUtils_CollectStaticMeshes", "Collecting Static Meshes for Cluster")));
			SlowTask.MakeDialog();
			for (auto& Actor : LODActor->SubActors)
			{
				TArray<UStaticMeshComponent*> Components;

				if (Actor->IsA<ALODActor>())
				{
					ExtractStaticMeshComponentsFromLODActor(Actor, Components);
				}
				else
				{
					Actor->GetComponents<UStaticMeshComponent>(Components);
				}

				// TODO: support instanced static meshes
				Components.RemoveAll([](UStaticMeshComponent* Val){ return Val->IsA(UInstancedStaticMeshComponent::StaticClass()); });

				AllComponents.Append(Components);
				SlowTask.EnterProgressFrame(1);
			}
		}

		// it shouldn't even have come here if it didn't have any staticmesh
		if (ensure(AllComponents.Num() > 0))
		{
			FScopedSlowTask SlowTask(LODActor->SubActors.Num(), (LOCTEXT("HierarchicalLODUtils_MergingMeshes", "Merging Static Meshes and creating LODActor")));
			SlowTask.MakeDialog();

			// In case we don't have outer generated assets should have same path as LOD level
			const FString AssetsPath = AssetsOuter->GetName() + TEXT("/");
			AActor* FirstActor = LODActor->SubActors[0];

			TArray<UObject*> OutAssets;
			FVector OutProxyLocation = FVector::ZeroVector;
			UStaticMesh* MainMesh = nullptr;

			// Generate proxy mesh and proxy material assets
			IMeshUtilities& MeshUtilities = FModuleManager::Get().LoadModuleChecked<IMeshUtilities>("MeshUtilities");
			// should give unique name, so use level + actor name
			const FString PackageName = FString::Printf(TEXT("LOD_%s"), *FirstActor->GetName());
			if (MeshUtilities.GetMeshMergingInterface() && LODSetup.bSimplifyMesh)
			{
				TArray<AActor*> Actors;
				ExtractSubActorsFromLODActor(LODActor, Actors);

				FHierarchicalLODUtilities& Module = FModuleManager::LoadModuleChecked<FHierarchicalLODUtilities>("HierarchicalLODUtilities");
				FHierarchicalLODProxyProcessor* Processor = Module.GetProxyProcessor();

				FHierarchicalSimplification OverrideLODSetup = LODSetup;

				FMeshProxySettings ProxySettings = LODSetup.ProxySetting;
				if (LODActor->bOverrideMaterialMergeSettings)
				{
					ProxySettings.MaterialSettings = LODActor->MaterialSettings;
				}

				if (LODActor->bOverrideScreenSize)
				{
					ProxySettings.ScreenSize = LODActor->ScreenSize;
				}

				if (LODActor->bOverrideTransitionScreenSize)
				{
					OverrideLODSetup.TransitionScreenSize = LODActor->TransitionScreenSize;
				}

				FGuid JobID = Processor->AddProxyJob(LODActor, OverrideLODSetup);
				MeshUtilities.CreateProxyMesh(Actors, ProxySettings, AssetsOuter, PackageName, JobID, Processor->GetCallbackDelegate(), true, OverrideLODSetup.TransitionScreenSize);
				return true;
			}
			else
			{
				FMeshMergingSettings MergeSettings = LODSetup.MergeSetting;
				if (LODActor->bOverrideMaterialMergeSettings)
				{
					MergeSettings.MaterialSettings = LODActor->MaterialSettings;
				}

				MeshUtilities.MergeStaticMeshComponents(AllComponents, FirstActor->GetWorld(), MergeSettings, AssetsOuter, PackageName, LODIndex, OutAssets, OutProxyLocation, LODSetup.TransitionScreenSize, true);
				
				// set staticmesh
				for (auto& Asset : OutAssets)
				{
					UStaticMesh* StaticMesh = Cast<UStaticMesh>(Asset);

					if (StaticMesh)
					{
						MainMesh = StaticMesh;
					}
				}

				LODActor->SetStaticMesh(MainMesh);
				LODActor->SetActorLocation(OutProxyLocation);
				LODActor->SubObjects = OutAssets;

				// At the moment this assumes a fixed field of view of 90 degrees (horizontal and vertical axi)
				static const float FOVRad = 90.0f * (float)PI / 360.0f;
				static const FMatrix ProjectionMatrix = FPerspectiveMatrix(FOVRad, 1920, 1080, 0.01f);
				FBoxSphereBounds Bounds = LODActor->GetStaticMeshComponent()->CalcBounds(FTransform());
				LODActor->LODDrawDistance = FHierarchicalLODUtilities::CalculateDrawDistanceFromScreenSize(Bounds.SphereRadius, LODSetup.TransitionScreenSize, ProjectionMatrix);
				LODActor->UpdateSubActorLODParents();

				// Freshly build so mark not dirty
				LODActor->SetIsDirty(false);

				return true;
			}
		}
	}
	return false;
}
Пример #22
0
void AFlarePlanetarium::SetupCelestialBody(CelestialBodyPosition* BodyPosition, double DisplayDistance, double DisplayRadius)
{
	FVector PlayerShipLocation = FVector::ZeroVector;
	if (GetGame()->GetPC()->GetShipPawn())
	{
		PlayerShipLocation = GetGame()->GetPC()->GetShipPawn()->GetActorLocation();
	}

#ifdef PLANETARIUM_DEBUG
	DrawDebugSphere(GetWorld(), FVector::ZeroVector, DisplayDistance /1000 , 32, FColor::Blue, false);

	PlayerShipLocation = FVector::ZeroVector;
	DisplayRadius /= 1000;
	DisplayDistance /= 1000;
#endif

	BodyPosition->BodyComponent->SetRelativeLocation((DisplayDistance * BodyPosition->AlignedLocation.GetUnsafeNormal()).ToVector() + PlayerShipLocation);

	float Scale = DisplayRadius / 512; // Mesh size is 1024;
	BodyPosition->BodyComponent->SetRelativeScale3D(FPreciseVector(Scale).ToVector());

	FTransform BaseRotation = FTransform(FRotator(0, 0 ,90));
	FTransform TimeRotation = FTransform(FRotator(0, BodyPosition->TotalRotation, 0));

	FQuat Rotation = (TimeRotation * BaseRotation).GetRotation();

	// TODO Rotation float time interpolation
	BodyPosition->BodyComponent->SetRelativeRotation(FQuat::Identity);
	BodyPosition->BodyComponent->SetRelativeRotation(Rotation);

	// Apply sun direction to component
	UMaterialInstanceDynamic* ComponentMaterial = Cast<UMaterialInstanceDynamic>(BodyPosition->BodyComponent->GetMaterial(0));
	if (!ComponentMaterial)
	{
		ComponentMaterial = UMaterialInstanceDynamic::Create(BodyPosition->BodyComponent->GetMaterial(0) , GetWorld());
		BodyPosition->BodyComponent->SetMaterial(0, ComponentMaterial);
	}
	ComponentMaterial->SetVectorParameterValue("SunDirection", SunDirection.ToVector());

	// Look for rings and orient them
	TArray<USceneComponent*> RingCandidates;
	BodyPosition->BodyComponent->GetChildrenComponents(true, RingCandidates);
	for (int32 ComponentIndex = 0; ComponentIndex < RingCandidates.Num(); ComponentIndex++)
	{
		UStaticMeshComponent* RingComponent = Cast<UStaticMeshComponent>(RingCandidates[ComponentIndex]);

		if (RingComponent && RingComponent->GetName().Contains("ring"))
		{
			// Get or create the material
			UMaterialInstanceDynamic* RingMaterial = Cast<UMaterialInstanceDynamic>(RingComponent->GetMaterial(0));
			if (!RingMaterial)
			{
				RingMaterial = UMaterialInstanceDynamic::Create(RingComponent->GetMaterial(0), GetWorld());
				RingComponent->SetMaterial(0, RingMaterial);
			}

			// Get world-space rotation angles for the ring and the sun
			float SunRotationPitch = FMath::RadiansToDegrees(FMath::Atan2(SunDirection.Z,SunDirection.X)) + 180;
			float RingRotationPitch = -BodyPosition->TotalRotation;

			// Feed params to the shader
			RingMaterial->SetScalarParameterValue("RingPitch", RingRotationPitch / 360);
			RingMaterial->SetScalarParameterValue("SunPitch", SunRotationPitch / 360);
		}
	}

	// Sun also rotates to track direction
	if (BodyPosition->Body == &Sun)
	{
		BodyPosition->BodyComponent->SetRelativeRotation(SunDirection.ToVector().Rotation());
	}

	// Compute sun occlusion
	if (BodyPosition->Body != &Sun)
	{
		double OcclusionAngle = FPreciseMath::Asin(BodyPosition->Radius / BodyPosition->Distance);



		float BodyPhase =  FMath::UnwindRadians(FMath::Atan2(BodyPosition->AlignedLocation.Z, BodyPosition->AlignedLocation.X));
		float CenterAngularDistance = FMath::Abs(FMath::UnwindRadians(SunPhase - BodyPhase));
		float AngleSum = (SunOcclusionAngle + OcclusionAngle);
		float AngleDiff = FMath::Abs(SunOcclusionAngle - OcclusionAngle);

		/*FLOGV("SetupCelestialBody %s BodyPhase = %f", *BodyPosition->Body->Name.ToString(), FMath::RadiansToDegrees(BodyPhase));
		FLOGV("SetupCelestialBody %s SunPhase = %f", *BodyPosition->Body->Name.ToString(), FMath::RadiansToDegrees(SunPhase));
		FLOGV("SetupCelestialBody %s OcclusionAngle = %f", *BodyPosition->Body->Name.ToString(), FMath::RadiansToDegrees(OcclusionAngle));
		FLOGV("SetupCelestialBody %s SunOcclusionAngle = %f", *BodyPosition->Body->Name.ToString(), FMath::RadiansToDegrees(SunOcclusionAngle));
		FLOGV("SetupCelestialBody %s AngleDiff = %f", *BodyPosition->Body->Name.ToString(), FMath::RadiansToDegrees(AngleDiff));

		FLOGV("SetupCelestialBody %s CenterAngularDistance = %f", *BodyPosition->Body->Name.ToString(), FMath::RadiansToDegrees(CenterAngularDistance));
		FLOGV("SetupCelestialBody %s AngleSum = %f", *BodyPosition->Body->Name.ToString(), FMath::RadiansToDegrees(AngleSum));*/


		if (CenterAngularDistance < AngleSum)
		{
			// There is occlusion
			float OcclusionRatio;

			if (CenterAngularDistance < AngleDiff)
			{
				// Maximum occlusion
				OcclusionRatio = 1.0;
			}
			else
			{
				// Partial occlusion
				OcclusionRatio = (AngleSum - CenterAngularDistance) / (2* FMath::Min(SunOcclusionAngle, OcclusionAngle));

				// OcclusionRatio = ((SunOcclusionAngle + OcclusionAngle) + FMath::Max(SunOcclusionAngle, OcclusionAngle) - FMath::Min(SunOcclusionAngle, OcclusionAngle)) / (2 * CenterAngularDistance);
			}
			//FLOGV("MoveCelestialBody %s OcclusionRatio = %f", *Body->Name, OcclusionRatio);

			// Now, find the surface occlusion
			float SunAngularSurface = PI*FMath::Square(SunOcclusionAngle);
			float MaxOcclusionAngularSurface = PI*FMath::Square(FMath::Min(SunOcclusionAngle, OcclusionAngle));
			float MaxOcclusion = MaxOcclusionAngularSurface / SunAngularSurface;
			float Occlusion = OcclusionRatio * MaxOcclusion;

			/*FLOGV("SetupCelestialBody %s CenterAngularDistance = %f", *BodyPosition->Body->Name.ToString(), CenterAngularDistance);
			FLOGV("SetupCelestialBody %s SunOcclusionAngle = %f", *BodyPosition->Body->Name.ToString(), SunOcclusionAngle);
			FLOGV("SetupCelestialBody %s OcclusionAngle = %f", *BodyPosition->Body->Name.ToString(), OcclusionAngle);
			FLOGV("SetupCelestialBody %s SunAngularSurface = %f", *BodyPosition->Body->Name.ToString(), SunAngularSurface);
			FLOGV("SetupCelestialBody %s MaxOcclusionAngularSurface = %f", *BodyPosition->Body->Name.ToString(), MaxOcclusionAngularSurface);
			FLOGV("SetupCelestialBody %s MaxOcclusion = %f", *BodyPosition->Body->Name.ToString(), MaxOcclusion);
			FLOGV("SetupCelestialBody %s Occlusion = %f", *BodyPosition->Body->Name.ToString(), Occlusion);*/

			if (Occlusion > SunOcclusion)
			{
				// Keep only best occlusion
				SunOcclusion = Occlusion;
			}
		}
	}

}
void UPhysicsHandleComponent::SetTargetLocationAndRotation(FVector NewLocation, FRotator NewRotation)
{
	TargetTransform = FTransform(NewRotation, NewLocation);
}