I finally found the solution by using a FMinimalViewInfo
and a FSceneViewProjectionData
. Though there still was some transformation problem, which I fixed by looking at the UGamePlayStatics:ProjectWorldToScreen( APlayerController const* PlayerController, const FVector & WorldPosition, FVector2D & ScreenPosition, bool bPlayerViewportRelative )
code. They applied some magic rotation matrix which I still dont get, but it works! xD
So now, here is my code:
bool UMyPixelUtility::calcBoundingFromViewInfo(USceneCaptureComponent2D * RenderComponent, FVector Origin, FVector Extend, FBox2D & BoxOut, TArray<FVector>& Points, TArray<FVector2D>& Points2D)
{
bool isCompletelyInView = true;
// get render target for texture size
UTextureRenderTarget2D* RenderTexture = RenderComponent->TextureTarget;
FRenderTarget *RenderTarget = RenderTexture->GameThread_GetRenderTargetResource();
// initialise viewinfo for projection matrix
FMinimalViewInfo Info;
Info.Location = RenderComponent->GetComponentTransform().GetLocation();
Info.Rotation = RenderComponent->GetComponentTransform().GetRotation().Rotator();
Info.FOV = RenderComponent->FOVAngle;
Info.ProjectionMode = RenderComponent->ProjectionType;
Info.AspectRatio = float(RenderTexture->SizeX) / float(RenderTexture->SizeY);
Info.OrthoNearClipPlane = 1;
Info.OrthoFarClipPlane = 1000;
Info.bConstrainAspectRatio = true;
// calculate 3D corner Points of bounding box
Points.Add(Origin + FVector(Extend.X, Extend.Y, Extend.Z));
Points.Add(Origin + FVector(-Extend.X, Extend.Y, Extend.Z));
Points.Add(Origin + FVector(Extend.X, -Extend.Y, Extend.Z));
Points.Add(Origin + FVector(-Extend.X, -Extend.Y, Extend.Z));
Points.Add(Origin + FVector(Extend.X, Extend.Y, -Extend.Z));
Points.Add(Origin + FVector(-Extend.X, Extend.Y, -Extend.Z));
Points.Add(Origin + FVector(Extend.X, -Extend.Y, -Extend.Z));
Points.Add(Origin + FVector(-Extend.X, -Extend.Y, -Extend.Z));
// initialize pixel values
FVector2D MinPixel(RenderTexture->SizeX, RenderTexture->SizeY);
FVector2D MaxPixel(0, 0);
FIntRect ScreenRect(0, 0, RenderTexture->SizeX, RenderTexture->SizeY);
// initialize projection data for sceneview
FSceneViewProjectionData ProjectionData;
ProjectionData.ViewOrigin = Info.Location;
// do some voodoo rotation that is somehow mandatory and stolen from UGameplayStatics::ProjectWorldToScreen
ProjectionData.ViewRotationMatrix = FInverseRotationMatrix(Info.Rotation) * FMatrix(
FPlane(0, 0, 1, 0),
FPlane(1, 0, 0, 0),
FPlane(0, 1, 0, 0),
FPlane(0, 0, 0, 1));
if (RenderComponent->bUseCustomProjectionMatrix == true) {
ProjectionData.ProjectionMatrix = RenderComponent->CustomProjectionMatrix;
}
else {
ProjectionData.ProjectionMatrix = Info.CalculateProjectionMatrix();;
}
ProjectionData.SetConstrainedViewRectangle(ScreenRect);
// Project Points to pixels and get the corner pixels
for (FVector& Point : Points) {
FVector2D Pixel(0, 0);
FSceneView::ProjectWorldToScreen((Point), ScreenRect, ProjectionData.ComputeViewProjectionMatrix(), Pixel);
Points2D.Add(Pixel);
MaxPixel.X = FMath::Max(Pixel.X, MaxPixel.X);
MaxPixel.Y = FMath::Max(Pixel.Y, MaxPixel.Y);
MinPixel.X = FMath::Min(Pixel.X, MinPixel.X);
MinPixel.Y = FMath::Min(Pixel.Y, MinPixel.Y);
}
BoxOut = FBox2D(MinPixel, MaxPixel);
// clamp min point
if (BoxOut.Min.X < 0) {
BoxOut.Min.X = 0;
isCompletelyInView = false;
}
else if (BoxOut.Min.X > RenderTexture->SizeX) {
BoxOut.Min.X = RenderTexture->SizeX;
isCompletelyInView = false;
}
if (BoxOut.Min.Y < 0) {
BoxOut.Min.Y = 0;
isCompletelyInView = false;
}
else if (BoxOut.Min.Y > RenderTexture->SizeY) {
BoxOut.Min.Y = RenderTexture->SizeY;
isCompletelyInView = false;
}
// clamp max point
if (BoxOut.Max.X > RenderTexture->SizeX) {
BoxOut.Max.X = RenderTexture->SizeX;
isCompletelyInView = false;
}
else if (BoxOut.Max.X < 0) {
BoxOut.Max.X = 0;
isCompletelyInView = false;
}
if (BoxOut.Max.Y > RenderTexture->SizeY) {
BoxOut.Max.Y = RenderTexture->SizeY;
isCompletelyInView = false;
}
else if (BoxOut.Max.Y < 0) {
BoxOut.Max.Y = 0;
isCompletelyInView = false;
}
return isCompletelyInView;
}
(I added some clamping to the texture size when the actor is not in view)