off-axis projection in unreal

2023. 5. 16. 16:32unreal engine

나중에 로컬 플레이어, 플레이어 컨트롤러를 바꿔줘야 함

 

 

//RaceController.h : 플레이어 컨트롤러

UCLASS()
class KLSRACE_API ARaceController : public APlayerController
{
GENERATED_BODY()

public:
URaceCamera* lPlayer;

public:
virtual void BeginPlay() override;
virtual void Tick(float deltaSeconds) override;
};

//RaceController.cpp : 플레이어 컨트롤러
void ARaceController::BeginPlay()
{
Super::BeginPlay();
lPlayer = (URaceCamera*)GetLocalPlayer();
SetShowMouseCursor(true);
}

void ARaceController::Tick(float deltaSeconds)
{
float mouseX, mouseY;
if (GetMousePosition(mouseX, mouseY))
{
if (lPlayer)
{
auto XY = lPlayer->ViewportClient->Viewport->GetSizeXY();
float mX = 0.0f - (mouseX - XY.X / 2) / XY.X;
float mY = (mouseY - XY.Y / 2) / XY.Y; //UE상하 좌표축 반대
lPlayer->EyePosition.Set(mX * 2.0f, mY * 2.0f);
}
}
}

//RaceCamera.h : 로컬 플레이어
UCLASS()
class KLSRACE_API URaceCamera : public ULocalPlayer
{
GENERATED_BODY()

public:
UPROPERTY(BlueprintReadWrite, EditAnywhere)
FVector2D EyePosition;

public:
URaceCamera(FVTableHelper& Helper) : Super(Helper) 

//relative positions : abs(0~1)
EyePosition.Set(0, 0);
}

virtual FSceneView* CalcSceneView(class FSceneViewFamily* ViewFamily,
FVector& OutViewLocation,
FRotator& OutViewRotation,
FViewport* Viewport,
class FViewElementDrawer* ViewDrawer = NULL,
int32 StereoViewIndex = INDEX_NONE);

};


//RaceCamera.cpp : 로컬 플레이어

FSceneView* URaceCamera::CalcSceneView(
class FSceneViewFamily* ViewFamily, 
FVector& OutViewLocation, 
FRotator& OutViewRotation, 
FViewport* Viewport, 
class FViewElementDrawer* ViewDrawer /*= NULL*/, 
int32 StereoViewIndex /*= eSSP_FULL*/)
{
    auto View = ULocalPlayer::CalcSceneView(ViewFamily, OutViewLocation, OutViewRotation, Viewport, ViewDrawer, StereoViewIndex);

    if (View)
{
//Get Original ViewInfo : 이건 계산한 다음에 원래 카메라에 잡힌 fov와 가로세로 비율을 적용해 주기 위함.
FMinimalViewInfo ViewInfo;
GetViewPoint(ViewInfo);

// to compute screen edges and screen axes
auto screenSize = Viewport->GetSizeXY();
FVector pa(screenSize.X * -0.5f, screenSize.Y * -0.5f, GNearClippingPlane); //lower left
FVector pb(screenSize.X * 0.5f, screenSize.Y * -0.5f, GNearClippingPlane); //lower right
FVector pc(screenSize.X * -0.5f, screenSize.Y * 0.5f, GNearClippingPlane); //upper left

// compute eye position
FVector pe(EyePosition.X, EyePosition.Y, -1);

// to compute projection matrix
FVector va = pa - pe; // from pe to pa
FVector vb = pb - pe; // from pe to pb
FVector vc = pc - pe; // from pe to pc
FVector vr = pb - pa; // right axis of screen
FVector vu = pc - pa; // up axis of screen
FVector vn = FVector::CrossProduct(vr, vu); // normal vector of screen
vr.Normalize(); //right
vu.Normalize(); //up
vn.Normalize(); //normal

float n = GNearClippingPlane; //near : GNearClippingPlane은 따로 정의되어 있어서 가져올 수 있다.
float f = 10000.0f; //far
float d = -FVector::DotProduct(va, vn); // distance from eye to screen(ratio)
float nd = n / d; // distance from eye to screen
float l = FVector::DotProduct(vr, va) * nd; // distance to left screen edge
float r = FVector::DotProduct(vr, vb) * nd; // distance to right screen edge
float b = FVector::DotProduct(vu, va) * nd; // distance to bottom screen edge
float t = FVector::DotProduct(vu, vc) * nd; // distance to top screen edge

//projection matrix
FMatrix offAxis = FMatrix::Identity;

offAxis.M[0][0] = -2.0f * n / (r - l);
offAxis.M[0][1] = 0;
offAxis.M[0][2] = 0;
offAxis.M[0][3] = 0;

offAxis.M[1][0] = 0;
offAxis.M[1][1] = -2.0f * n / (t - b);
offAxis.M[1][2] = 0;
offAxis.M[1][3] = 0;

offAxis.M[2][0] = -(r + l) / (r - l);
offAxis.M[2][1] = -(t + b) / (t - b);
offAxis.M[2][2] = (f + n) / (f - n);
offAxis.M[2][3] = 1;

offAxis.M[3][0] = 0;
offAxis.M[3][1] = 0;
offAxis.M[3][2] = (2.0f * f * n) / (f - n);
offAxis.M[3][3] = 0;

FMatrix rm = FMatrix::Identity; //Rotation Matrix
rm.M[0][0] = vr.X;
rm.M[0][1] = vr.Y;
rm.M[0][2] = vr.Z;

rm.M[1][0] = vu.X;
rm.M[1][1] = vu.Y;
rm.M[1][2] = vu.Z;

rm.M[2][0] = vn.X;
rm.M[2][1] = vn.Y;
rm.M[2][2] = vn.Z;

FMatrix tm = FMatrix::Identity; //Translation Matrix
tm.M[3][0] = -pe.X;
tm.M[3][1] = -pe.Y;
tm.M[3][2] = -pe.Z;

FMatrix prj = tm * (offAxis * rm);

prj.M[2][2] = 0.0f;
prj.M[3][0] = 0.0f;
prj.M[3][1] = 0.0f;

prj *= 1.0f / prj.M[0][0];
float FOVratio = 1.0f / FMath::Tan(FMath::Max(0.001f, ViewInfo.FOV) * (float)PI / 360.0f);
prj.M[0][0] *= FOVratio;
prj.M[1][1] *= FOVratio;
prj.M[2][0] *= GNearClippingPlane;
prj.M[2][1] *= GNearClippingPlane;
prj.M[2][3] = 1;
prj.M[3][2] = GNearClippingPlane;

//Update Projection Matrix
View->ProjectionMatrixUnadjustedForRHI = prj;

FMatrix* pProjectionMatrix = (FMatrix*)(&View->ViewMatrices.GetProjectionMatrix());
*pProjectionMatrix = AdjustProjectionMatrixForRHI(View->ProjectionMatrixUnadjustedForRHI);
//GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, offAxis.ToString());

FMatrix* pViewProjectionMatrix = (FMatrix*)(&View->ViewMatrices.GetViewProjectionMatrix());
*pViewProjectionMatrix = View->ViewMatrices.GetViewMatrix() * View->ViewMatrices.GetProjectionMatrix();

FMatrix* pInvViewProjectionMatrix = (FMatrix*)&View->ViewMatrices.GetInvViewProjectionMatrix();
*pInvViewProjectionMatrix = View->ViewMatrices.GetViewProjectionMatrix().Inverse();

FMatrix TranslatedViewMatrix = FTranslationMatrix(-View->ViewMatrices.GetPreViewTranslation()) * View->ViewMatrices.GetViewMatrix();

FMatrix* pTranslatedViewProjectionMatrix = (FMatrix*)(&View->ViewMatrices.GetTranslatedViewProjectionMatrix());
*pTranslatedViewProjectionMatrix = TranslatedViewMatrix * View->ViewMatrices.GetProjectionMatrix();

FMatrix* pInvTranslatedViewProjectionMatrixx = (FMatrix*)(&View->ViewMatrices.GetInvTranslatedViewProjectionMatrix());
*pInvTranslatedViewProjectionMatrixx = View->ViewMatrices.GetTranslatedViewProjectionMatrix().Inverse();

View->ShadowViewMatrices = View->ViewMatrices;
GetViewFrustumBounds(View->ViewFrustum, View->ViewMatrices.GetViewProjectionMatrix(), false);
    }


    return View;
}

'unreal engine' 카테고리의 다른 글

Tickable Object  (0) 2024.02.23
Unreal 에서 Opencv를 이용한 webcam 화면 불러오기  (0) 2023.08.23
Animation이 적용된 Skeletal Mesh  (0) 2023.05.13
Gradient Material  (0) 2023.05.11
지형용 머터리얼 만들기 → 적용  (0) 2023.03.28