FBoxSphereBounds UPaperGroupedSpriteComponent::CalcBounds(const FTransform& BoundTransform) const { bool bHadAnyBounds = false; FBoxSphereBounds NewBounds(ForceInit); if (PerInstanceSpriteData.Num() > 0) { const FMatrix BoundTransformMatrix = BoundTransform.ToMatrixWithScale(); for (const FSpriteInstanceData& InstanceData : PerInstanceSpriteData) { if (InstanceData.SourceSprite != nullptr) { const FBoxSphereBounds RenderBounds = InstanceData.SourceSprite->GetRenderBounds(); const FBoxSphereBounds InstanceBounds = RenderBounds.TransformBy(InstanceData.Transform * BoundTransformMatrix); if (bHadAnyBounds) { NewBounds = NewBounds + InstanceBounds; } else { NewBounds = InstanceBounds; bHadAnyBounds = true; } } } } return bHadAnyBounds ? NewBounds : FBoxSphereBounds(BoundTransform.GetLocation(), FVector::ZeroVector, 0.f); }
FBoxSphereBounds UPaperTerrainComponent::CalcBounds(const FTransform& LocalToWorld) const { // Determine the rendering bounds FBoxSphereBounds LocalRenderBounds; { FBox BoundingBox(ForceInit); for (const FPaperTerrainSpriteGeometry& DrawCall : GeneratedSpriteGeometry) { for (const FSpriteDrawCallRecord& Record : DrawCall.Records) { for (const FVector4& VertXYUV : Record.RenderVerts) { const FVector Vert((PaperAxisX * VertXYUV.X) + (PaperAxisY * VertXYUV.Y)); BoundingBox += Vert; } } } // Make the whole thing a single unit 'deep' const FVector HalfThicknessVector = 0.5f * PaperAxisZ; BoundingBox.Min -= HalfThicknessVector; BoundingBox.Max += HalfThicknessVector; LocalRenderBounds = FBoxSphereBounds(BoundingBox); } // Graphics bounds. FBoxSphereBounds NewBounds = LocalRenderBounds.TransformBy(LocalToWorld); // Add bounds of collision geometry (if present). if (CachedBodySetup != nullptr) { const FBox AggGeomBox = CachedBodySetup->AggGeom.CalcAABB(LocalToWorld); if (AggGeomBox.IsValid) { NewBounds = Union(NewBounds, FBoxSphereBounds(AggGeomBox)); } } // Apply bounds scale NewBounds.BoxExtent *= BoundsScale; NewBounds.SphereRadius *= BoundsScale; return NewBounds; }
bool UPostProcessComponent::EncompassesPoint(FVector Point, float SphereRadius/*=0.f*/, float* OutDistanceToPoint) { UShapeComponent* ParentShape = Cast<UShapeComponent>(GetAttachParent()); if (ParentShape != nullptr) { #if WITH_PHYSX FVector ClosestPoint; float Distance = ParentShape->GetDistanceToCollision(Point, ClosestPoint); #else FBoxSphereBounds Bounds = ParentShape->CalcBounds(ParentShape->ComponentToWorld); float Distance = 0; if (ParentShape->IsA<USphereComponent>()) { const FSphere& Sphere = Bounds.GetSphere(); const FVector& Dist = Sphere.Center - Point; Distance = FMath::Max(0.0f, Dist.Size() - Sphere.W); } else // UBox or UCapsule shape (approx). { Distance = FMath::Sqrt(Bounds.GetBox().ComputeSquaredDistanceToPoint(Point)); } #endif if (OutDistanceToPoint) { *OutDistanceToPoint = Distance; } return Distance >= 0.f && Distance <= SphereRadius; } if (OutDistanceToPoint != nullptr) { *OutDistanceToPoint = 0; } return true; }
bool UDebugSkelMeshComponent::CheckIfBoundsAreCorrrect() { if (GetPhysicsAsset()) { bool bWasUsingInGameBounds = IsUsingInGameBounds(); FTransform TempTransform = FTransform::Identity; UseInGameBounds(true); FBoxSphereBounds InGameBounds = CalcBounds(TempTransform); UseInGameBounds(false); FBoxSphereBounds PreviewBounds = CalcBounds(TempTransform); UseInGameBounds(bWasUsingInGameBounds); // calculate again to have bounds as requested CalcBounds(TempTransform); // if in-game bounds are of almost same size as preview bounds or bigger, it seems to be fine if (! InGameBounds.GetSphere().IsInside(PreviewBounds.GetSphere(), PreviewBounds.GetSphere().W * 0.1f) && // for spheres: A.IsInside(B) checks if A is inside of B ! PreviewBounds.GetBox().IsInside(InGameBounds.GetBox().ExpandBy(PreviewBounds.GetSphere().W * 0.1f))) // for boxes: A.IsInside(B) checks if B is inside of A { return true; } } return false; }
FVector UTextRenderComponent::GetTextWorldSize() const { FBoxSphereBounds Bounds = CalcBounds(ComponentToWorld); return Bounds.GetBox().GetSize(); }
FVector UTextRenderComponent::GetTextLocalSize() const { FBoxSphereBounds Bounds = CalcBounds(FTransform::Identity); return Bounds.GetBox().GetSize(); }
void UPaperSpriteThumbnailRenderer::DrawFrame(class UPaperSprite* Sprite, int32 X, int32 Y, uint32 Width, uint32 Height, FRenderTarget*, FCanvas* Canvas, FBoxSphereBounds* OverrideRenderBounds) { const UTexture2D* SourceTexture = nullptr; if (Sprite != nullptr) { SourceTexture = Sprite->GetBakedTexture() ? Sprite->GetBakedTexture() : Sprite->GetSourceTexture(); } if (SourceTexture != nullptr) { const bool bUseTranslucentBlend = SourceTexture->HasAlphaChannel(); // Draw the grid behind the sprite if (bUseTranslucentBlend) { DrawGrid(X, Y, Width, Height, Canvas); } // Draw the sprite itself // Use the baked render data, so we don't have to care about rotations and possibly // other sprites overlapping in source, UV region, etc. const TArray<FVector4>& BakedRenderData = Sprite->BakedRenderData; TArray<FVector2D> CanvasPositions; TArray<FVector2D> CanvasUVs; for (int Vertex = 0; Vertex < BakedRenderData.Num(); ++Vertex) { new (CanvasPositions) FVector2D(BakedRenderData[Vertex].X, BakedRenderData[Vertex].Y); new (CanvasUVs) FVector2D(BakedRenderData[Vertex].Z, BakedRenderData[Vertex].W); } // Determine the bounds to use FBoxSphereBounds* RenderBounds = OverrideRenderBounds; FBoxSphereBounds FrameBounds; if (RenderBounds == nullptr) { FrameBounds = Sprite->GetRenderBounds(); RenderBounds = &FrameBounds; } const FVector MinPoint3D = RenderBounds->GetBoxExtrema(0); const FVector MaxPoint3D = RenderBounds->GetBoxExtrema(1); const FVector2D MinPoint(FVector::DotProduct(MinPoint3D, PaperAxisX), FVector::DotProduct(MinPoint3D, PaperAxisY)); const FVector2D MaxPoint(FVector::DotProduct(MaxPoint3D, PaperAxisX), FVector::DotProduct(MaxPoint3D, PaperAxisY)); const float UnscaledWidth = MaxPoint.X - MinPoint.X; const float UnscaledHeight = MaxPoint.Y - MinPoint.Y; const FVector2D Origin(X + Width * 0.5f, Y + Height * 0.5f); const bool bIsWider = (UnscaledWidth > 0.0f) && (UnscaledHeight > 0.0f) && (UnscaledWidth > UnscaledHeight); const float ScaleFactor = bIsWider ? (Width / UnscaledWidth) : (Height / UnscaledHeight); // Scale and recenter const FVector2D CanvasPositionCenter = (MaxPoint + MinPoint) * 0.5f; for (int Vertex = 0; Vertex < CanvasPositions.Num(); ++Vertex) { CanvasPositions[Vertex] = (CanvasPositions[Vertex] - CanvasPositionCenter) * ScaleFactor + Origin; CanvasPositions[Vertex].Y = Height - CanvasPositions[Vertex].Y; } // Draw triangles if ((CanvasPositions.Num() > 0) && (SourceTexture->Resource != nullptr)) { TArray<FCanvasUVTri> Triangles; const FLinearColor SpriteColor(FLinearColor::White); for (int Vertex = 0; Vertex < CanvasPositions.Num(); Vertex += 3) { FCanvasUVTri* Triangle = new (Triangles) FCanvasUVTri(); Triangle->V0_Pos = CanvasPositions[Vertex + 0]; Triangle->V0_UV = CanvasUVs[Vertex + 0]; Triangle->V0_Color = SpriteColor; Triangle->V1_Pos = CanvasPositions[Vertex + 1]; Triangle->V1_UV = CanvasUVs[Vertex + 1]; Triangle->V1_Color = SpriteColor; Triangle->V2_Pos = CanvasPositions[Vertex + 2]; Triangle->V2_UV = CanvasUVs[Vertex + 2]; Triangle->V2_Color = SpriteColor; } FCanvasTriangleItem CanvasTriangle(Triangles, SourceTexture->Resource); CanvasTriangle.BlendMode = bUseTranslucentBlend ? ESimpleElementBlendMode::SE_BLEND_Translucent : ESimpleElementBlendMode::SE_BLEND_Opaque; Canvas->DrawItem(CanvasTriangle); } } else { // Fallback for a bogus sprite DrawGrid(X, Y, Width, Height, Canvas); } }
bool FVertexSnappingImpl::SnapDraggedActorsToNearestVertex( FVector& DragDelta, FLevelEditorViewportClient* ViewportClient ) { int32 MouseX = ViewportClient->Viewport->GetMouseX(); int32 MouseY = ViewportClient->Viewport->GetMouseY(); FVector2D MousePosition = FVector2D( MouseX, MouseY ) ; EAxisList::Type CurrentAxis = ViewportClient->GetCurrentWidgetAxis(); bool bSnapped = false; if( !DragDelta.IsNearlyZero() ) { // Are there selected actors? USelection* Selection = GEditor->GetSelectedActors(); FVector Direction = DragDelta.GetSafeNormal(); FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues( ViewportClient->Viewport, ViewportClient->GetScene(), ViewportClient->EngineShowFlags ) .SetRealtimeUpdate( ViewportClient->IsRealtime() )); FSceneView* View = ViewportClient->CalcSceneView( &ViewFamily ); FVector StartLocation = ViewportClient->GetModeTools()->PivotLocation; FVector DesiredUnsnappedLocation = StartLocation+DragDelta; // Plane facing in the direction of axis movement. This is for clipping actors which are behind the desired location (they should not be considered for snap) FPlane ActorPlane( DesiredUnsnappedLocation, Direction ); TSet< TWeakObjectPtr<AActor> > ActorsToIgnore; // Snap each selected actor for ( FSelectionIterator It( GEditor->GetSelectedActorIterator() ) ; It ; ++It ) { // Build up a region that actors must be in for snapping FBoxSphereBounds SnappingAreaBox( FBox( DesiredUnsnappedLocation-VertexSnappingConstants::MaxSnappingDistance, DesiredUnsnappedLocation+VertexSnappingConstants::MaxSnappingDistance ) ); AActor* Actor = CastChecked<AActor>( *It ); if( Actor->GetRootComponent() != NULL ) { // Get a bounding box around the actor const bool bNonColliding = true; FBoxSphereBounds ActorBounds = Actor->GetComponentsBoundingBox(bNonColliding); // The allowed snapping box is a box around the selected actor plus a region around the actor that other actors must be in for snapping FBox AllowedSnappingBox = ActorBounds.GetBox(); // Extend the box to include the drag point AllowedSnappingBox += SnappingAreaBox.GetBox(); GetActorsToIgnore( Actor, ActorsToIgnore ); FVertexSnappingArgs Args ( ActorPlane, DesiredUnsnappedLocation, ViewportClient, View, MousePosition, CurrentAxis, true ); // Snap the drag delta SnapDragDelta( Args, StartLocation, AllowedSnappingBox, ActorsToIgnore, DragDelta ); } } } return bSnapped; }