void AGameplayAbilityWorldReticle::FaceTowardSource(bool bFaceIn2D) { if (TargetingActor) { if (bFaceIn2D) { FVector FacingVector = (TargetingActor->StartLocation.GetTargetingTransform().GetLocation() - GetActorLocation()).GetSafeNormal2D(); if (FacingVector.IsZero()) { FacingVector = -GetActorForwardVector().GetSafeNormal2D(); } if (!FacingVector.IsZero()) { SetActorRotation(FacingVector.Rotation()); } } else { FVector FacingVector = (TargetingActor->StartLocation.GetTargetingTransform().GetLocation() - GetActorLocation()).GetSafeNormal(); if (FacingVector.IsZero()) { FacingVector = -GetActorForwardVector().GetSafeNormal(); } SetActorRotation(FacingVector.Rotation()); } } }
void AGameplayAbilityTargetActor_Trace::AimWithPlayerController(const AActor* InSourceActor, FCollisionQueryParams Params, const FVector& TraceStart, FVector& OutTraceEnd, bool bIgnorePitch) const { if (!OwningAbility) // Server and launching client only { return; } APlayerController* PC = OwningAbility->GetCurrentActorInfo()->PlayerController.Get(); check(PC); FVector ViewStart; FRotator ViewRot; PC->GetPlayerViewPoint(ViewStart, ViewRot); const FVector ViewDir = ViewRot.Vector(); FVector ViewEnd = ViewStart + (ViewDir * MaxRange); ClipCameraRayToAbilityRange(ViewStart, ViewDir, TraceStart, MaxRange, ViewEnd); FHitResult HitResult; LineTraceWithFilter(HitResult, InSourceActor->GetWorld(), Filter, ViewStart, ViewEnd, TraceProfile.Name, Params); const bool bUseTraceResult = HitResult.bBlockingHit && (FVector::DistSquared(TraceStart, HitResult.Location) <= (MaxRange * MaxRange)); const FVector AdjustedEnd = (bUseTraceResult) ? HitResult.Location : ViewEnd; FVector AdjustedAimDir = (AdjustedEnd - TraceStart).GetSafeNormal(); if (AdjustedAimDir.IsZero()) { AdjustedAimDir = ViewDir; } if (!bTraceAffectsAimPitch && bUseTraceResult) { FVector OriginalAimDir = (ViewEnd - TraceStart).GetSafeNormal(); if (!OriginalAimDir.IsZero()) { // Convert to angles and use original pitch const FRotator OriginalAimRot = OriginalAimDir.Rotation(); FRotator AdjustedAimRot = AdjustedAimDir.Rotation(); AdjustedAimRot.Pitch = OriginalAimRot.Pitch; AdjustedAimDir = AdjustedAimRot.Vector(); } } OutTraceEnd = TraceStart + (AdjustedAimDir * MaxRange); }
EBTNodeResult::Type URandomWander::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) { UBlackboardComponent* Blackboard = OwnerComp.GetBlackboardComponent(); if (!GetWorld()) { return EBTNodeResult::Failed; } FVector NewWaypoint = FVector::ZeroVector; FVector CurrentPos = Blackboard->GetOwner()->GetActorLocation(); NewWaypoint.X = CurrentPos.X + FMath::FRandRange(-5000, 5000); NewWaypoint.Y = CurrentPos.Y + FMath::FRandRange(-5000, 5000); while (FVector::Dist(NewWaypoint, Blackboard->GetOwner()->GetActorLocation()) <= 2000.f && TraceFromPosition(OutResult, 100.f, ECollisionChannel::ECC_EngineTraceChannel1, NewWaypoint, OwnerComp) == false) { NewWaypoint.X = CurrentPos.X + FMath::FRandRange(-5000, 5000); NewWaypoint.Y = CurrentPos.Y + FMath::FRandRange(-5000, 5000); } if (!NewWaypoint.IsZero()) { Blackboard->SetValue<UBlackboardKeyType_Vector>(BlackboardKey.GetSelectedKeyID(), NewWaypoint); return EBTNodeResult::Succeeded; } return EBTNodeResult::Failed; }
void AAIController::UpdateControlRotation(float DeltaTime, bool bUpdatePawn) { // Look toward focus FVector FocalPoint = GetFocalPoint(); if( !FocalPoint.IsZero() && GetPawn()) { FVector Direction = FocalPoint - GetPawn()->GetActorLocation(); FRotator NewControlRotation = Direction.Rotation(); // Don't pitch view of walking pawns unless looking at another pawn if ( GetPawn()->GetMovementComponent() && GetPawn()->GetMovementComponent()->IsMovingOnGround() && PathFollowingComponent && (!PathFollowingComponent->GetMoveGoal() || !Cast<APawn>(PathFollowingComponent->GetMoveGoal()) ) ) { NewControlRotation.Pitch = 0.f; } NewControlRotation.Yaw = FRotator::ClampAxis(NewControlRotation.Yaw); SetControlRotation(NewControlRotation); APawn* const P = GetPawn(); if (P && bUpdatePawn) { P->FaceRotation(NewControlRotation, DeltaTime); } } }
/** Utility for calculating drag direction when you click on this widget. */ void HWidgetUtilProxy::CalcVectors(FSceneView* SceneView, const FViewportClick& Click, FVector& LocalManDir, FVector& WorldManDir, float& DragDirX, float& DragDirY) { if(Axis == EAxisList::X) { WorldManDir = WidgetMatrix.GetScaledAxis( EAxis::X ); LocalManDir = FVector(1,0,0); } else if(Axis == EAxisList::Y) { WorldManDir = WidgetMatrix.GetScaledAxis( EAxis::Y ); LocalManDir = FVector(0,1,0); } else { WorldManDir = WidgetMatrix.GetScaledAxis( EAxis::Z ); LocalManDir = FVector(0,0,1); } FVector WorldDragDir = WorldManDir; if(Mode == WMM_Rotate) { if( FMath::Abs(Click.GetDirection() | WorldManDir) > KINDA_SMALL_NUMBER ) // If click direction and circle plane are parallel.. can't resolve. { // First, find actual position we clicking on the circle in world space. const FVector ClickPosition = FMath::LinePlaneIntersection( Click.GetOrigin(), Click.GetOrigin() + Click.GetDirection(), WidgetMatrix.GetOrigin(), WorldManDir ); // Then find Radial direction vector (from center to widget to clicked position). FVector RadialDir = ( ClickPosition - WidgetMatrix.GetOrigin() ); RadialDir.Normalize(); // Then tangent in plane is just the cross product. Should always be unit length again because RadialDir and WorlManDir should be orthogonal. WorldDragDir = RadialDir ^ WorldManDir; } } // Transform world-space drag dir to screen space. FVector ScreenDir = SceneView->ViewMatrices.ViewMatrix.TransformVector(WorldDragDir); ScreenDir.Z = 0.0f; if( ScreenDir.IsZero() ) { DragDirX = 0.0f; DragDirY = 0.0f; } else { ScreenDir.Normalize(); DragDirX = ScreenDir.X; DragDirY = ScreenDir.Y; } }
void DrawDebugCylinder(const UWorld* InWorld, FVector const& Start, FVector const& End, float Radius, int32 Segments, FColor const& Color, bool bPersistentLines, float LifeTime, uint8 DepthPriority) { // no debug line drawing on dedicated server if (GEngine->GetNetMode(InWorld) != NM_DedicatedServer) { // Need at least 4 segments Segments = FMath::Max(Segments, 4); // Rotate a point around axis to form cylinder segments FVector Segment; FVector P1, P2, P3, P4; const int32 AngleInc = 360.f / Segments; int32 Angle = AngleInc; // Default for Axis is up FVector Axis = (End - Start).SafeNormal(); if( Axis.IsZero() ) { Axis = FVector(0.f, 0.f, 1.f); } FVector Perpendicular; FVector Dummy; Axis.FindBestAxisVectors(Perpendicular, Dummy); Segment = Perpendicular.RotateAngleAxis(0, Axis) * Radius; P1 = Segment + Start; P3 = Segment + End; // this means foreground lines can't be persistent ULineBatchComponent* const LineBatcher = GetDebugLineBatcher( InWorld, bPersistentLines, LifeTime, (DepthPriority == SDPG_Foreground) ); if(LineBatcher != NULL) { while( Segments-- ) { Segment = Perpendicular.RotateAngleAxis(Angle, Axis) * Radius; P2 = Segment + Start; P4 = Segment + End; LineBatcher->DrawLine(P2, P4, Color, DepthPriority); LineBatcher->DrawLine(P1, P2, Color, DepthPriority); LineBatcher->DrawLine(P3, P4, Color, DepthPriority); P1 = P2; P3 = P4; Angle += AngleInc; } } } }
bool AController::LineOfSightTo(const AActor* Other, FVector ViewPoint, bool bAlternateChecks) { if( !Other ) { return false; } if ( ViewPoint.IsZero() ) { AActor* ViewTarg = GetViewTarget(); ViewPoint = ViewTarg->GetActorLocation(); if( ViewTarg == Pawn ) { ViewPoint.Z += Pawn->BaseEyeHeight; //look from eyes } } static FName NAME_LineOfSight = FName(TEXT("LineOfSight")); FCollisionQueryParams CollisionParms(NAME_LineOfSight, true, Other); CollisionParms.AddIgnoredActor(this->GetPawn()); FVector TargetLocation = Other->GetTargetLocation(Pawn); bool bHit = GetWorld()->LineTraceTest(ViewPoint, TargetLocation, ECC_Visibility, CollisionParms); if( !bHit ) { return true; } // if other isn't using a cylinder for collision and isn't a Pawn (which already requires an accurate cylinder for AI) // then don't go any further as it likely will not be tracing to the correct location if (!Cast<const APawn>(Other) && Cast<UCapsuleComponent>(Other->GetRootComponent()) == NULL) { return false; } float distSq = (Other->GetActorLocation() - ViewPoint).SizeSquared(); if ( distSq > FARSIGHTTHRESHOLDSQUARED ) { return false; } if ( !Cast<const APawn>(Other) && (distSq > NEARSIGHTTHRESHOLDSQUARED) ) { return false; } float OtherRadius, OtherHeight; Other->GetSimpleCollisionCylinder(OtherRadius, OtherHeight); //try viewpoint to head bHit = GetWorld()->LineTraceTest(ViewPoint, Other->GetActorLocation() + FVector(0.f,0.f,OtherHeight), ECC_Visibility, CollisionParms); return !bHit; }
static FVector CombineAdjustments(FVector CurrentAdjustment, FVector AdjustmentToAdd) { // remove the part of the new adjustment that's parallel to the current adjustment if (CurrentAdjustment.IsZero()) { return AdjustmentToAdd; } FVector Projection = AdjustmentToAdd.ProjectOnTo(CurrentAdjustment); Projection = Projection.GetClampedToMaxSize(CurrentAdjustment.Size()); FVector OrthogalAdjustmentToAdd = AdjustmentToAdd - Projection; return CurrentAdjustment + OrthogalAdjustmentToAdd; }
FVector GetMovementBaseVelocity(const UPrimitiveComponent* MovementBase, const FName BoneName) { FVector BaseVelocity = FVector::ZeroVector; if (MovementBaseUtility::IsDynamicBase(MovementBase)) { if (BoneName != NAME_None) { const FBodyInstance* BodyInstance = MovementBase->GetBodyInstance(BoneName); if (BodyInstance) { BaseVelocity = BodyInstance->GetUnrealWorldVelocity(); return BaseVelocity; } } BaseVelocity = MovementBase->GetComponentVelocity(); if (BaseVelocity.IsZero()) { // Fall back to actor's Root component const AActor* Owner = MovementBase->GetOwner(); if (Owner) { // Component might be moved manually (not by simulated physics or a movement component), see if the root component of the actor has a velocity. BaseVelocity = MovementBase->GetOwner()->GetVelocity(); } } // Fall back to physics velocity. if (BaseVelocity.IsZero() && MovementBase->GetBodyInstance()) { BaseVelocity = MovementBase->GetBodyInstance()->GetUnrealWorldVelocity(); } } return BaseVelocity; }
float UTKMathFunctionLibrary::ConvertPhysicsLinearVelocity(FVector Velocity, TEnumAsByte<enum ESpeedUnit> SpeedUnit) { if (Velocity.IsZero()) return 0.f; float unit = 0; switch (SpeedUnit) { case CentimeterPerSecond: unit = 1; break; case FootPerSecond: unit = 0.03280839895013; break; case MeterPerSecond: unit = 0.01; break; case MeterPerMinute: unit = 0.6; break; case KilometerPerSecond: unit = 0.00001; case KilometerPerMinute: unit = 0.0006; break; case KilometerPerHour: unit = 0.036; break; case MilePerHour: unit = 0.02236936292054; break; case Knot: unit = 0.01943844492441; break; case Mach: unit = 0.00002915451895044; break; case SpeedOfLight: unit = 3.335640951982E-11; break; case YardPerSecond: unit = 0.01093613298338; break; default: break; }; return Velocity.Size() * unit; }
static void DrawAngles(FCanvas* Canvas, int32 XPos, int32 YPos, EAxisList::Type ManipAxis, FWidget::EWidgetMode MoveMode, const FRotator& Rotation, const FVector& Translation) { FString OutputString(TEXT("")); if (MoveMode == FWidget::WM_Rotate && Rotation.IsZero() == false) { //Only one value moves at a time const FVector EulerAngles = Rotation.Euler(); if (ManipAxis == EAxisList::X) { OutputString += FString::Printf(TEXT("Roll: %0.2f"), EulerAngles.X); } else if (ManipAxis == EAxisList::Y) { OutputString += FString::Printf(TEXT("Pitch: %0.2f"), EulerAngles.Y); } else if (ManipAxis == EAxisList::Z) { OutputString += FString::Printf(TEXT("Yaw: %0.2f"), EulerAngles.Z); } } else if (MoveMode == FWidget::WM_Translate && Translation.IsZero() == false) { //Only one value moves at a time if (ManipAxis == EAxisList::X) { OutputString += FString::Printf(TEXT(" %0.2f"), Translation.X); } else if (ManipAxis == EAxisList::Y) { OutputString += FString::Printf(TEXT(" %0.2f"), Translation.Y); } else if (ManipAxis == EAxisList::Z) { OutputString += FString::Printf(TEXT(" %0.2f"), Translation.Z); } } if (OutputString.Len() > 0) { FCanvasTextItem TextItem( FVector2D(XPos, YPos), FText::FromString( OutputString ), GEngine->GetSmallFont(), FLinearColor::White ); Canvas->DrawItem( TextItem ); } }
bool UAoEHeal::Activate(class AMech_RPGCharacter* target, FVector targetLocation) { if (!targetLocation.IsZero()) { FTempAOESettings settings; settings.affectedTeam = GetAffectedTeam(); settings.healthChange = GetWeaponHealthChange() * healAmount; settings.owner = owner; settings.world = owner->GetWorld(); settings.rate = 0.5F; settings.radius = 700; settings.location = targetLocation; settings.damageType = DamageEnums::Blast; settings.duration = 3.0F; settings.usesTarget = false; settings.heals = true; AAOEHealthChange::CreateAOEHealthChange(settings); SetOnCooldown(owner->GetWorld()); return true; } return false; }
bool AAIController::LineOfSightTo(const AActor* Other, FVector ViewPoint, bool bAlternateChecks) const { if (Other == nullptr) { return false; } if (ViewPoint.IsZero()) { FRotator ViewRotation; GetActorEyesViewPoint(ViewPoint, ViewRotation); // if we still don't have a view point we simply fail if (ViewPoint.IsZero()) { return false; } } static FName NAME_LineOfSight = FName(TEXT("LineOfSight")); FVector TargetLocation = Other->GetTargetLocation(GetPawn()); FCollisionQueryParams CollisionParams(NAME_LineOfSight, true, this->GetPawn()); CollisionParams.AddIgnoredActor(Other); bool bHit = GetWorld()->LineTraceTestByChannel(ViewPoint, TargetLocation, ECC_Visibility, CollisionParams); if (!bHit) { return true; } // if other isn't using a cylinder for collision and isn't a Pawn (which already requires an accurate cylinder for AI) // then don't go any further as it likely will not be tracing to the correct location const APawn * OtherPawn = Cast<const APawn>(Other); if (!OtherPawn && Cast<UCapsuleComponent>(Other->GetRootComponent()) == NULL) { return false; } const FVector OtherActorLocation = Other->GetActorLocation(); const float DistSq = (OtherActorLocation - ViewPoint).SizeSquared(); if (DistSq > FARSIGHTTHRESHOLDSQUARED) { return false; } if (!OtherPawn && (DistSq > NEARSIGHTTHRESHOLDSQUARED)) { return false; } float OtherRadius, OtherHeight; Other->GetSimpleCollisionCylinder(OtherRadius, OtherHeight); if (!bAlternateChecks || !bLOSflag) { //try viewpoint to head bHit = GetWorld()->LineTraceTestByChannel(ViewPoint, OtherActorLocation + FVector(0.f, 0.f, OtherHeight), ECC_Visibility, CollisionParams); if (!bHit) { return true; } } if (!bSkipExtraLOSChecks && (!bAlternateChecks || bLOSflag)) { // only check sides if width of other is significant compared to distance if (OtherRadius * OtherRadius / (OtherActorLocation - ViewPoint).SizeSquared() < 0.0001f) { return false; } //try checking sides - look at dist to four side points, and cull furthest and closest FVector Points[4]; Points[0] = OtherActorLocation - FVector(OtherRadius, -1 * OtherRadius, 0); Points[1] = OtherActorLocation + FVector(OtherRadius, OtherRadius, 0); Points[2] = OtherActorLocation - FVector(OtherRadius, OtherRadius, 0); Points[3] = OtherActorLocation + FVector(OtherRadius, -1 * OtherRadius, 0); int32 IndexMin = 0; int32 IndexMax = 0; float CurrentMax = (Points[0] - ViewPoint).SizeSquared(); float CurrentMin = CurrentMax; for (int32 PointIndex = 1; PointIndex<4; PointIndex++) { const float NextSize = (Points[PointIndex] - ViewPoint).SizeSquared(); if (NextSize > CurrentMin) { CurrentMin = NextSize; IndexMax = PointIndex; } else if (NextSize < CurrentMax) { CurrentMax = NextSize; IndexMin = PointIndex; } } for (int32 PointIndex = 0; PointIndex<4; PointIndex++) { if ((PointIndex != IndexMin) && (PointIndex != IndexMax)) { bHit = GetWorld()->LineTraceTestByChannel(ViewPoint, Points[PointIndex], ECC_Visibility, CollisionParams); if (!bHit) { return true; } } } } return false; }
/** * @return true if the delta was handled by this editor mode tool. */ bool FModeTool_Texture::InputDelta(FEditorViewportClient* InViewportClient,FViewport* InViewport,FVector& InDrag,FRotator& InRot,FVector& InScale) { if( InViewportClient->GetCurrentWidgetAxis() == EAxisList::None ) { return false; } // calculate delta drag for this tick for the call to GEditor->polyTexPan below which is using relative (delta) mode FVector deltaDrag = InDrag; if (true == InViewportClient->IsPerspective()) { // perspective viewports pass the absolute drag so subtract the last tick's drag value to get the delta deltaDrag -= PreviousInputDrag; } PreviousInputDrag = InDrag; if( !deltaDrag.IsZero() ) { // Ensure each polygon has a unique base point index. for( FConstLevelIterator Iterator = InViewportClient->GetWorld()->GetLevelIterator(); Iterator; ++Iterator ) { UModel* Model = (*Iterator)->Model; for(int32 SurfaceIndex = 0;SurfaceIndex < Model->Surfs.Num();SurfaceIndex++) { FBspSurf& Surf = Model->Surfs[SurfaceIndex]; if(Surf.PolyFlags & PF_Selected) { const FVector Base = Model->Points[Surf.pBase]; Surf.pBase = Model->Points.Add(Base); } } FMatrix Mat = GLevelEditorModeTools().GetCustomDrawingCoordinateSystem(); FVector UVW = Mat.InverseTransformVector( deltaDrag ); // InverseTransformNormal because Mat is the transform from the surface/widget's coords to world coords GEditor->polyTexPan( Model, UVW.X, UVW.Y, 0 ); // 0 is relative mode because UVW is made from deltaDrag - the user input since the last tick } } if( !InRot.IsZero() ) { const FRotationMatrix RotationMatrix( InRot ); // Ensure each polygon has unique texture vector indices. for ( TSelectedSurfaceIterator<> It(InViewportClient->GetWorld()) ; It ; ++It ) { FBspSurf* Surf = *It; UModel* Model = It.GetModel(); FVector TextureU = Model->Vectors[Surf->vTextureU]; FVector TextureV = Model->Vectors[Surf->vTextureV]; TextureU = RotationMatrix.TransformPosition( TextureU ); TextureV = RotationMatrix.TransformPosition( TextureV ); Surf->vTextureU = Model->Vectors.Add(TextureU); Surf->vTextureV = Model->Vectors.Add(TextureV); const bool bUpdateTexCoords = true; const bool bOnlyRefreshSurfaceMaterials = true; GEditor->polyUpdateMaster(Model, It.GetSurfaceIndex(), bUpdateTexCoords, bOnlyRefreshSurfaceMaterials); } } if( !InScale.IsZero() ) { float ScaleU = InScale.X / GEditor->GetGridSize(); float ScaleV = InScale.Y / GEditor->GetGridSize(); ScaleU = 1.f - (ScaleU / 100.f); ScaleV = 1.f - (ScaleV / 100.f); // Ensure each polygon has unique texture vector indices. for( FConstLevelIterator Iterator = InViewportClient->GetWorld()->GetLevelIterator(); Iterator; ++Iterator ) { UModel* Model = (*Iterator)->Model; for(int32 SurfaceIndex = 0;SurfaceIndex < Model->Surfs.Num();SurfaceIndex++) { FBspSurf& Surf = Model->Surfs[SurfaceIndex]; if(Surf.PolyFlags & PF_Selected) { const FVector TextureU = Model->Vectors[Surf.vTextureU]; const FVector TextureV = Model->Vectors[Surf.vTextureV]; Surf.vTextureU = Model->Vectors.Add(TextureU); Surf.vTextureV = Model->Vectors.Add(TextureV); } } GEditor->polyTexScale( Model, ScaleU, 0.f, 0.f, ScaleV, false ); } } return true; }
bool UMovementComponent::ResolvePenetrationImpl(const FVector& ProposedAdjustment, const FHitResult& Hit, const FQuat& NewRotationQuat) { // SceneComponent can't be in penetration, so this function really only applies to PrimitiveComponent. const FVector Adjustment = ConstrainDirectionToPlane(ProposedAdjustment); if (!Adjustment.IsZero() && UpdatedPrimitive) { // See if we can fit at the adjusted location without overlapping anything. AActor* ActorOwner = UpdatedComponent->GetOwner(); if (!ActorOwner) { return false; } UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration: %s.%s at location %s inside %s.%s at location %s by %.3f (netmode: %d)"), *ActorOwner->GetName(), *UpdatedComponent->GetName(), *UpdatedComponent->GetComponentLocation().ToString(), *GetNameSafe(Hit.GetActor()), *GetNameSafe(Hit.GetComponent()), Hit.Component.IsValid() ? *Hit.GetComponent()->GetComponentLocation().ToString() : TEXT("<unknown>"), Hit.PenetrationDepth, (uint32)GetNetMode()); // We really want to make sure that precision differences or differences between the overlap test and sweep tests don't put us into another overlap, // so make the overlap test a bit more restrictive. const float OverlapInflation = CVarPenetrationOverlapCheckInflation.GetValueOnGameThread(); bool bEncroached = OverlapTest(Hit.TraceStart + Adjustment, NewRotationQuat, UpdatedPrimitive->GetCollisionObjectType(), UpdatedPrimitive->GetCollisionShape(OverlapInflation), ActorOwner); if (!bEncroached) { // Move without sweeping. MoveUpdatedComponent(Adjustment, NewRotationQuat, false, nullptr, ETeleportType::TeleportPhysics); UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration: teleport by %s"), *Adjustment.ToString()); return true; } else { // Disable MOVECOMP_NeverIgnoreBlockingOverlaps if it is enabled, otherwise we wouldn't be able to sweep out of the object to fix the penetration. TGuardValue<EMoveComponentFlags> ScopedFlagRestore(MoveComponentFlags, EMoveComponentFlags(MoveComponentFlags & (~MOVECOMP_NeverIgnoreBlockingOverlaps))); // Try sweeping as far as possible... FHitResult SweepOutHit(1.f); bool bMoved = MoveUpdatedComponent(Adjustment, NewRotationQuat, true, &SweepOutHit, ETeleportType::TeleportPhysics); UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration: sweep by %s (success = %d)"), *Adjustment.ToString(), bMoved); // Still stuck? if (!bMoved && SweepOutHit.bStartPenetrating) { // Combine two MTD results to get a new direction that gets out of multiple surfaces. const FVector SecondMTD = GetPenetrationAdjustment(SweepOutHit); const FVector CombinedMTD = Adjustment + SecondMTD; if (SecondMTD != Adjustment && !CombinedMTD.IsZero()) { bMoved = MoveUpdatedComponent(CombinedMTD, NewRotationQuat, true, nullptr, ETeleportType::TeleportPhysics); UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration: sweep by %s (MTD combo success = %d)"), *CombinedMTD.ToString(), bMoved); } } // Still stuck? if (!bMoved) { // Try moving the proposed adjustment plus the attempted move direction. This can sometimes get out of penetrations with multiple objects const FVector MoveDelta = ConstrainDirectionToPlane(Hit.TraceEnd - Hit.TraceStart); if (!MoveDelta.IsZero()) { bMoved = MoveUpdatedComponent(Adjustment + MoveDelta, NewRotationQuat, true, nullptr, ETeleportType::TeleportPhysics); UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration: sweep by %s (adjusted attempt success = %d)"), *(Adjustment + MoveDelta).ToString(), bMoved); } } return bMoved; } } return false; }
bool AAIController::LineOfSightTo(const AActor* Other, FVector ViewPoint, bool bAlternateChecks) { if( !Other ) { return false; } if ( ViewPoint.IsZero() ) { AActor* ViewTarg = GetViewTarget(); ViewPoint = ViewTarg->GetActorLocation(); if( ViewTarg == GetPawn() ) { ViewPoint.Z += GetPawn()->BaseEyeHeight; //look from eyes } } static FName NAME_LineOfSight = FName(TEXT("LineOfSight")); FVector TargetLocation = Other->GetTargetLocation(GetPawn()); FCollisionQueryParams CollisionParams(NAME_LineOfSight, true, this->GetPawn()); CollisionParams.AddIgnoredActor(Other); bool bHit = GetWorld()->LineTraceTest(ViewPoint, TargetLocation, ECC_Visibility, CollisionParams); if( !bHit ) { return true; } // if other isn't using a cylinder for collision and isn't a Pawn (which already requires an accurate cylinder for AI) // then don't go any further as it likely will not be tracing to the correct location const APawn * OtherPawn = Cast<const APawn>(Other); if (!OtherPawn && Cast<UCapsuleComponent>(Other->GetRootComponent()) == NULL) { return false; } const FVector OtherActorLocation = Other->GetActorLocation(); float distSq = (OtherActorLocation - ViewPoint).SizeSquared(); if ( distSq > FARSIGHTTHRESHOLDSQUARED ) { return false; } if ( !OtherPawn && (distSq > NEARSIGHTTHRESHOLDSQUARED) ) { return false; } float OtherRadius, OtherHeight; Other->GetSimpleCollisionCylinder(OtherRadius, OtherHeight); if ( !bAlternateChecks || !bLOSflag ) { //try viewpoint to head bHit = GetWorld()->LineTraceTest(ViewPoint, OtherActorLocation + FVector(0.f,0.f,OtherHeight), ECC_Visibility, CollisionParams); if ( !bHit ) { return true; } } if( !bSkipExtraLOSChecks && (!bAlternateChecks || bLOSflag) ) { // only check sides if width of other is significant compared to distance if( OtherRadius * OtherRadius/(OtherActorLocation - ViewPoint).SizeSquared() < 0.0001f ) { return false; } //try checking sides - look at dist to four side points, and cull furthest and closest FVector Points[4]; Points[0] = OtherActorLocation - FVector(OtherRadius, -1 * OtherRadius, 0); Points[1] = OtherActorLocation + FVector(OtherRadius, OtherRadius, 0); Points[2] = OtherActorLocation - FVector(OtherRadius, OtherRadius, 0); Points[3] = OtherActorLocation + FVector(OtherRadius, -1 * OtherRadius, 0); int32 imin = 0; int32 imax = 0; float currentmin = (Points[0] - ViewPoint).SizeSquared(); float currentmax = currentmin; for ( int32 i=1; i<4; i++ ) { float nextsize = (Points[i] - ViewPoint).SizeSquared(); if (nextsize > currentmax) { currentmax = nextsize; imax = i; } else if (nextsize < currentmin) { currentmin = nextsize; imin = i; } } for ( int32 i=0; i<4; i++ ) { if ( (i != imin) && (i != imax) ) { bHit = GetWorld()->LineTraceTest(ViewPoint, Points[i], ECC_Visibility, CollisionParams); if ( !bHit ) { return true; } } } } return false; }
TArray<FColor> USceneCapturer::SaveAtlas(FString Folder, const TArray<FColor>& SurfaceData) { SCOPE_CYCLE_COUNTER( STAT_SPSavePNG ); TArray<FColor> SphericalAtlas; SphericalAtlas.AddZeroed(SphericalAtlasWidth * SphericalAtlasHeight); const FVector2D slicePlaneDim = FVector2D( 2.0f * FMath::Tan(FMath::DegreesToRadians(sliceHFov) / 2.0f), 2.0f * FMath::Tan(FMath::DegreesToRadians(sliceVFov) / 2.0f)); //For each direction, // Find corresponding slice // Calculate intersection of slice plane // Calculate intersection UVs by projecting onto plane tangents // Supersample that UV coordinate from the unprojected atlas { SCOPE_CYCLE_COUNTER(STAT_SPSampleSpherical); // Dump out how long the process took const FDateTime SamplingStartTime = FDateTime::UtcNow(); UE_LOG(LogStereoPanorama, Log, TEXT("Sampling atlas...")); for (int32 y = 0; y < SphericalAtlasHeight; y++) { for (int32 x = 0; x < SphericalAtlasWidth; x++) { FLinearColor samplePixelAccum = FLinearColor(0, 0, 0, 0); //TODO: ikrimae: Seems that bilinear filtering sans supersampling is good enough. Supersampling sans bilerp seems best. // After more tests, come back to optimize by folding supersampling in and remove this outer sampling loop. const auto& ssPattern = g_ssPatterns[SSMethod]; for (int32 SampleCount = 0; SampleCount < ssPattern.numSamples; SampleCount++) { const float sampleU = ((float)x + ssPattern.ssOffsets[SampleCount].X) / SphericalAtlasWidth; const float sampleV = ((float)y + ssPattern.ssOffsets[SampleCount].Y) / SphericalAtlasHeight; const float sampleTheta = sampleU * 360.0f; const float samplePhi = sampleV * 180.0f; const FVector sampleDir = FVector( FMath::Sin(FMath::DegreesToRadians(samplePhi)) * FMath::Cos(FMath::DegreesToRadians(sampleTheta)), FMath::Sin(FMath::DegreesToRadians(samplePhi)) * FMath::Sin(FMath::DegreesToRadians(sampleTheta)), FMath::Cos(FMath::DegreesToRadians(samplePhi))); //TODO: ikrimae: ugh, ugly. const int32 sliceXIndex = FMath::TruncToInt(FRotator::ClampAxis(sampleTheta + hAngIncrement / 2.0f) / hAngIncrement); int32 sliceYIndex = 0; //Slice Selection = slice with max{sampleDir dot sliceNormal } { float largestCosAngle = 0; for (int VerticalStep = 0; VerticalStep < NumberOfVerticalSteps; VerticalStep++) { const FVector2D sliceCenterThetaPhi = FVector2D( hAngIncrement * sliceXIndex, vAngIncrement * VerticalStep); //TODO: ikrimae: There has got to be a faster way. Rethink reparametrization later const FVector sliceDir = FVector( FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.Y))); const float cosAngle = sampleDir | sliceDir; if (cosAngle > largestCosAngle) { largestCosAngle = cosAngle; sliceYIndex = VerticalStep; } } } const FVector2D sliceCenterThetaPhi = FVector2D( hAngIncrement * sliceXIndex, vAngIncrement * sliceYIndex); //TODO: ikrimae: Reparameterize with an inverse mapping (e.g. project from slice pixels onto final u,v coordinates. // Should make code simpler and faster b/c reduces to handful of sin/cos calcs per slice. // Supersampling will be more difficult though. const FVector sliceDir = FVector( FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.Y))); const FPlane slicePlane = FPlane(sliceDir, -sliceDir); //Tangents from partial derivatives of sphere equation const FVector slicePlanePhiTangent = FVector( FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), -FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y))).GetSafeNormal(); //Should be reconstructed to get around discontinuity of theta tangent at nodal points const FVector slicePlaneThetaTangent = (sliceDir ^ slicePlanePhiTangent).GetSafeNormal(); //const FVector slicePlaneThetaTangent = FVector( // -FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), // FMath::Sin(FMath::DegreesToRadians(sliceCenterThetaPhi.Y)) * FMath::Cos(FMath::DegreesToRadians(sliceCenterThetaPhi.X)), // 0).SafeNormal(); check(!slicePlaneThetaTangent.IsZero() && !slicePlanePhiTangent.IsZero()); const double t = (double)-slicePlane.W / (sampleDir | sliceDir); const FVector sliceIntersection = FVector(t * sampleDir.X, t * sampleDir.Y, t * sampleDir.Z); //Calculate scalar projection of sliceIntersection onto tangent vectors. a dot b / |b| = a dot b when tangent vectors are normalized //Then reparameterize to U,V of the sliceplane based on slice plane dimensions const float sliceU = (sliceIntersection | slicePlaneThetaTangent) / slicePlaneDim.X; const float sliceV = (sliceIntersection | slicePlanePhiTangent) / slicePlaneDim.Y; check(sliceU >= -(0.5f + KINDA_SMALL_NUMBER) && sliceU <= (0.5f + KINDA_SMALL_NUMBER)); check(sliceV >= -(0.5f + KINDA_SMALL_NUMBER) && sliceV <= (0.5f + KINDA_SMALL_NUMBER)); //TODO: ikrimae: Supersample/bilinear filter const int32 slicePixelX = FMath::TruncToInt(dbgMatchCaptureSliceFovToAtlasSliceFov ? sliceU * StripWidth : sliceU * CaptureWidth); const int32 slicePixelY = FMath::TruncToInt(dbgMatchCaptureSliceFovToAtlasSliceFov ? sliceV * StripHeight : sliceV * CaptureHeight); FLinearColor slicePixelSample; if (bEnableBilerp) { //TODO: ikrimae: Clean up later; too tired now const int32 sliceCenterPixelX = (sliceXIndex + 0.5f) * StripWidth; const int32 sliceCenterPixelY = (sliceYIndex + 0.5f) * StripHeight; const FIntPoint atlasSampleTL(sliceCenterPixelX + FMath::Clamp(slicePixelX , -StripWidth/2, StripWidth/2), sliceCenterPixelY + FMath::Clamp(slicePixelY , -StripHeight/2, StripHeight/2)); const FIntPoint atlasSampleTR(sliceCenterPixelX + FMath::Clamp(slicePixelX + 1, -StripWidth/2, StripWidth/2), sliceCenterPixelY + FMath::Clamp(slicePixelY , -StripHeight/2, StripHeight/2)); const FIntPoint atlasSampleBL(sliceCenterPixelX + FMath::Clamp(slicePixelX , -StripWidth/2, StripWidth/2), sliceCenterPixelY + FMath::Clamp(slicePixelY + 1, -StripHeight/2, StripHeight/2)); const FIntPoint atlasSampleBR(sliceCenterPixelX + FMath::Clamp(slicePixelX + 1, -StripWidth/2, StripWidth/2), sliceCenterPixelY + FMath::Clamp(slicePixelY + 1, -StripHeight/2, StripHeight/2)); const FColor pixelColorTL = SurfaceData[atlasSampleTL.Y * UnprojectedAtlasWidth + atlasSampleTL.X]; const FColor pixelColorTR = SurfaceData[atlasSampleTR.Y * UnprojectedAtlasWidth + atlasSampleTR.X]; const FColor pixelColorBL = SurfaceData[atlasSampleBL.Y * UnprojectedAtlasWidth + atlasSampleBL.X]; const FColor pixelColorBR = SurfaceData[atlasSampleBR.Y * UnprojectedAtlasWidth + atlasSampleBR.X]; const float fracX = FMath::Frac(dbgMatchCaptureSliceFovToAtlasSliceFov ? sliceU * StripWidth : sliceU * CaptureWidth); const float fracY = FMath::Frac(dbgMatchCaptureSliceFovToAtlasSliceFov ? sliceV * StripHeight : sliceV * CaptureHeight); //Reinterpret as linear (a.k.a dont apply srgb inversion) slicePixelSample = FMath::BiLerp( pixelColorTL.ReinterpretAsLinear(), pixelColorTR.ReinterpretAsLinear(), pixelColorBL.ReinterpretAsLinear(), pixelColorBR.ReinterpretAsLinear(), fracX, fracY); } else { const int32 sliceCenterPixelX = (sliceXIndex + 0.5f) * StripWidth; const int32 sliceCenterPixelY = (sliceYIndex + 0.5f) * StripHeight; const int32 atlasSampleX = sliceCenterPixelX + slicePixelX; const int32 atlasSampleY = sliceCenterPixelY + slicePixelY; slicePixelSample = SurfaceData[atlasSampleY * UnprojectedAtlasWidth + atlasSampleX].ReinterpretAsLinear(); } samplePixelAccum += slicePixelSample; ////Output color map of projections //const FColor debugEquiColors[12] = { // FColor(205, 180, 76), // FColor(190, 88, 202), // FColor(127, 185, 194), // FColor(90, 54, 47), // FColor(197, 88, 53), // FColor(197, 75, 124), // FColor(130, 208, 72), // FColor(136, 211, 153), // FColor(126, 130, 207), // FColor(83, 107, 59), // FColor(200, 160, 157), // FColor(80, 66, 106) //}; //samplePixelAccum = ssPattern.numSamples * debugEquiColors[sliceYIndex * 4 + sliceXIndex]; } SphericalAtlas[y * SphericalAtlasWidth + x] = (samplePixelAccum / ssPattern.numSamples).Quantize(); // Force alpha value if (bForceAlpha) { SphericalAtlas[y * SphericalAtlasWidth + x].A = 255; } } } //Blit the first column into the last column to make the stereo image seamless at theta=360 for (int32 y = 0; y < SphericalAtlasHeight; y++) { SphericalAtlas[y * SphericalAtlasWidth + (SphericalAtlasWidth - 1)] = SphericalAtlas[y * SphericalAtlasWidth + 0]; } const FTimespan SamplingDuration = FDateTime::UtcNow() - SamplingStartTime; UE_LOG(LogStereoPanorama, Log, TEXT("...done! Duration: %g seconds"), SamplingDuration.GetTotalSeconds()); } // Generate name FString FrameString = FString::Printf( TEXT( "%s_%05d.png" ), *Folder, CurrentFrameCount ); FString AtlasName = OutputDir / Timestamp / FrameString; UE_LOG( LogStereoPanorama, Log, TEXT( "Writing atlas: %s" ), *AtlasName ); // Write out PNG //TODO: ikrimae: Use threads to write out the images for performance IImageWrapperPtr ImageWrapper = ImageWrapperModule.CreateImageWrapper( EImageFormat::PNG ); ImageWrapper->SetRaw(SphericalAtlas.GetData(), SphericalAtlas.GetAllocatedSize(), SphericalAtlasWidth, SphericalAtlasHeight, ERGBFormat::BGRA, 8); const TArray<uint8>& PNGData = ImageWrapper->GetCompressed(100); FFileHelper::SaveArrayToFile( PNGData, *AtlasName ); if (FStereoPanoramaManager::GenerateDebugImages->GetInt() != 0) { FString FrameStringUnprojected = FString::Printf(TEXT("%s_%05d_Unprojected.png"), *Folder, CurrentFrameCount); FString AtlasNameUnprojected = OutputDir / Timestamp / FrameStringUnprojected; ImageWrapper->SetRaw(SurfaceData.GetData(), SurfaceData.GetAllocatedSize(), UnprojectedAtlasWidth, UnprojectedAtlasHeight, ERGBFormat::BGRA, 8); const TArray<uint8>& PNGDataUnprojected = ImageWrapper->GetCompressed(100); FFileHelper::SaveArrayToFile(PNGData, *AtlasNameUnprojected); } ImageWrapper.Reset(); UE_LOG( LogStereoPanorama, Log, TEXT( " ... done!" ), *AtlasName ); return SphericalAtlas; }
bool FSplineComponentVisualizer::HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, FRotator& DeltaRotate, FVector& DeltaScale) { USplineComponent* SplineComp = GetEditedSplineComponent(); if (SplineComp != nullptr) { FInterpCurveVector& SplineInfo = SplineComp->SplineInfo; FInterpCurveQuat& SplineRotInfo = SplineComp->SplineRotInfo; FInterpCurveVector& SplineScaleInfo = SplineComp->SplineScaleInfo; const int32 NumPoints = SplineInfo.Points.Num(); if (SelectedTangentHandle != INDEX_NONE) { // When tangent handles are manipulated... check(SelectedTangentHandle < NumPoints); if (!DeltaTranslate.IsZero()) { check(SelectedTangentHandleType != ESelectedTangentHandle::None); SplineComp->Modify(); FInterpCurvePoint<FVector>& EditedPoint = SplineInfo.Points[SelectedTangentHandle]; const FVector Delta = (SelectedTangentHandleType == ESelectedTangentHandle::Leave) ? DeltaTranslate : -DeltaTranslate; const FVector Tangent = EditedPoint.LeaveTangent + SplineComp->ComponentToWorld.InverseTransformVector(Delta); EditedPoint.LeaveTangent = Tangent; EditedPoint.ArriveTangent = Tangent; EditedPoint.InterpMode = CIM_CurveUser; } } else { // When spline keys are manipulated... check(LastKeyIndexSelected != INDEX_NONE); check(LastKeyIndexSelected < NumPoints); check(SelectedKeys.Num() > 0); SplineComp->Modify(); if (ViewportClient->IsAltPressed() && bAllowDuplication) { OnDuplicateKey(); // Don't duplicate again until we release LMB bAllowDuplication = false; } for (int32 SelectedKeyIndex : SelectedKeys) { FInterpCurvePoint<FVector>& EditedPoint = SplineInfo.Points[SelectedKeyIndex]; FInterpCurvePoint<FQuat>& EditedRotPoint = SplineRotInfo.Points[SelectedKeyIndex]; FInterpCurvePoint<FVector>& EditedScalePoint = SplineScaleInfo.Points[SelectedKeyIndex]; if (!DeltaTranslate.IsZero()) { // Find key position in world space const FVector CurrentWorldPos = SplineComp->ComponentToWorld.TransformPosition(EditedPoint.OutVal); // Move in world space const FVector NewWorldPos = CurrentWorldPos + DeltaTranslate; // Convert back to local space EditedPoint.OutVal = SplineComp->ComponentToWorld.InverseTransformPosition(NewWorldPos); } if (!DeltaRotate.IsZero()) { // Set point tangent as user controlled EditedPoint.InterpMode = CIM_CurveUser; // Rotate tangent according to delta rotation FVector NewTangent = SplineComp->ComponentToWorld.GetRotation().RotateVector(EditedPoint.LeaveTangent); // convert local-space tangent vector to world-space NewTangent = DeltaRotate.RotateVector(NewTangent); // apply world-space delta rotation to world-space tangent NewTangent = SplineComp->ComponentToWorld.GetRotation().Inverse().RotateVector(NewTangent); // convert world-space tangent vector back into local-space EditedPoint.LeaveTangent = NewTangent; EditedPoint.ArriveTangent = NewTangent; // Rotate spline rotation according to delta rotation FQuat NewRot = SplineComp->ComponentToWorld.GetRotation() * EditedRotPoint.OutVal; // convert local-space rotation to world-space NewRot = DeltaRotate.Quaternion() * NewRot; // apply world-space rotation NewRot = SplineComp->ComponentToWorld.GetRotation().Inverse() * NewRot; // convert world-space rotation to local-space EditedRotPoint.OutVal = NewRot; } if (DeltaScale.X != 0.0f) { // Set point tangent as user controlled EditedPoint.InterpMode = CIM_CurveUser; const FVector NewTangent = EditedPoint.LeaveTangent * (1.0f + DeltaScale.X); EditedPoint.LeaveTangent = NewTangent; EditedPoint.ArriveTangent = NewTangent; } if (DeltaScale.Y != 0.0f) { // Scale in Y adjusts the scale spline EditedScalePoint.OutVal.Y *= (1.0f + DeltaScale.Y); } if (DeltaScale.Z != 0.0f) { // Scale in Z adjusts the scale spline EditedScalePoint.OutVal.Z *= (1.0f + DeltaScale.Z); } } } NotifyComponentModified(); return true; } return false; }