Get Center Point on Face of Static Mesh

I can’t quite figure out what to do here. I’ve got a static mesh inside a UStaticMeshComponent, but its pivot is not near the actual mesh on purpose and the pivot also does not represent the rotation of the mesh. I need to get the point on the top face of my mesh as well as the rotation. If it helps, the reason I need to do this is because I want to align another actor on the surface of this mesh at the exact center. Unfortunately I can’t attach some sort of arrow or socket because this is all being generated in code.

Here is what i’ve tried so far…but none of it even comes close to working. I’m only posting this to show you i’m trying to work with getcomponentbounds and trying to create the rotation. The mesh does have collision, created on import…so maybe I can do something with that?

FVector Origin, Extent;
float SphereRadius;
UKismetSystemLibrary::GetComponentBounds(MeshComponent, Origin, Extent, SphereRadius);
FTransform OriginalTransform = this->GetActorTransform();
FVector OriginalLocation = OriginalTransform.GetLocation();
float Angle = FMath::RadiansToDegrees(acosf(FVector::DotProduct(Origin, Extent)));
FRotator RotationFromAngle = UKismetMathLibrary::RotatorFromAxisAndAngle(Origin, Angle);
APlanetAsset* Payload = GetWorld()->SpawnActor<APlanetAsset>(AssetClass, FVector::ZeroVector, FRotator::ZeroRotator);
Payload->AttachToComponent(RootComponent, FAttachmentTransformRules::KeepRelativeTransform, NAME_None);
Payload->SetActorRelativeLocation(Origin + Extent);
Payload->SetActorRelativeRotation(RotationFromAngle);

I used the SphereBounds of the static mesh component to obtain the center position of the actual mesh and then the radius to extent to center position to the outer edge. I also had to use a quaternion to calculate the rotation of the alignment rotation. I am setting the relative position of the spawned element. Here is the working code:

//Get the mesh sphere bounds
FBoxSphereBounds MeshBounds = MeshComponent->StaticMesh->GetBounds();
FVector MeshCenter = MeshBounds.GetSphere().Center;
float MeshRadius = MeshBounds.GetSphere().W;
FVector CompLocation = MeshComponent->GetComponentLocation();

//Get the spawn location
FVector Direction = UKismetMathLibrary::GetDirectionVector(CompLocation.UpVector, MeshCenter);
FVector SpawnLocation = Direction * (FVector::Dist(CompLocation.UpVector, MeshCenter) + MeshRadius);

//Spawn the asset actor
APlanetAsset* Payload = GetWorld()->SpawnActor<APlanetAsset>(AssetClass, SpawnLocation, FRotator::ZeroRotator);
Payload->AttachToComponent(MeshComponent, FAttachmentTransformRules::KeepRelativeTransform, NAME_None);

FVector StartLocation = Payload->GetActorLocation().UpVector;
FVector RotationV = FVector::CrossProduct(StartLocation, MeshCenter).UpVector;
FQuat RotationQuat = FQuat::FindBetweenVectors(StartLocation, MeshCenter);
float RotationAngle = FVector::DotProduct(StartLocation, MeshCenter);
RotationQuat.ToAxisAndAngle(RotationV, RotationAngle);

//Apply the rotation
Payload->SetActorRelativeRotation(RotationQuat.Rotator());
1 Like

Thank you for this! Quite a good solution for the problem.