Fix camera framing for large grids using corner projection
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f3f0c080a9
commit
344e5e221f
1 file changed
+50
-7
@@ -1,6 +1,8 @@
|
|||||||
#include "TacticaCameraPawn.h"
|
#include "TacticaCameraPawn.h"
|
||||||
#include "Camera/CameraComponent.h"
|
#include "Camera/CameraComponent.h"
|
||||||
#include "GridManager.h"
|
#include "GridManager.h"
|
||||||
|
#include "Engine/GameViewportClient.h"
|
||||||
|
#include "Engine/World.h"
|
||||||
#include "Kismet/GameplayStatics.h"
|
#include "Kismet/GameplayStatics.h"
|
||||||
|
|
||||||
DEFINE_LOG_CATEGORY_STATIC(LogTacticaCamera, Log, All);
|
DEFINE_LOG_CATEGORY_STATIC(LogTacticaCamera, Log, All);
|
||||||
@@ -25,12 +27,53 @@ void ATacticaCameraPawn::BeginPlay()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// グリッドの長辺の半分(余白つき)が画角に収まる距離を求める
|
|
||||||
const float HalfExtent = FMath::Max(Grid->GridSizeX, Grid->GridSizeY) * Grid->CellSize * 0.5f * MarginScale;
|
|
||||||
const float HalfFovRad = FMath::DegreesToRadians(Camera->FieldOfView * 0.5f);
|
|
||||||
const float Distance = HalfExtent / FMath::Tan(HalfFovRad);
|
|
||||||
|
|
||||||
const FRotator Rotation(Pitch, 0.0f, 0.0f);
|
const FRotator Rotation(Pitch, 0.0f, 0.0f);
|
||||||
const FVector Location = Grid->GetGridCenter() - Rotation.Vector() * Distance;
|
const FVector Center = Grid->GetGridCenter();
|
||||||
SetActorLocationAndRotation(Location, Rotation);
|
|
||||||
|
// 画面の縦横比(取れなければカメラの既定値)
|
||||||
|
float Aspect = Camera->AspectRatio;
|
||||||
|
if (const UWorld* World = GetWorld())
|
||||||
|
{
|
||||||
|
if (const UGameViewportClient* Viewport = World->GetGameViewport())
|
||||||
|
{
|
||||||
|
FVector2D Size;
|
||||||
|
Viewport->GetViewportSize(Size);
|
||||||
|
if (Size.X > 1.0f && Size.Y > 1.0f)
|
||||||
|
{
|
||||||
|
Aspect = Size.X / Size.Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 横方向・縦方向の画角の半分のtan(余白の分だけ狭めて使う)
|
||||||
|
const float TanH = FMath::Tan(FMath::DegreesToRadians(Camera->FieldOfView * 0.5f)) / MarginScale;
|
||||||
|
const float TanV = TanH / FMath::Max(Aspect, 0.1f);
|
||||||
|
|
||||||
|
// グリッドの四隅が画面に収まる最小の距離を求める。
|
||||||
|
// 斜めに見下ろすので、手前の辺は近く、奥の辺は遠い(深さが違う)ことを考慮する
|
||||||
|
const FRotationMatrix RotMatrix(Rotation);
|
||||||
|
const FVector ViewDir = RotMatrix.GetUnitAxis(EAxis::X);
|
||||||
|
const FVector Right = RotMatrix.GetUnitAxis(EAxis::Y);
|
||||||
|
const FVector Up = RotMatrix.GetUnitAxis(EAxis::Z);
|
||||||
|
|
||||||
|
const float HalfX = Grid->GridSizeX * Grid->CellSize * 0.5f;
|
||||||
|
const float HalfY = Grid->GridSizeY * Grid->CellSize * 0.5f;
|
||||||
|
|
||||||
|
float Distance = 0.0f;
|
||||||
|
for (int32 SignX = -1; SignX <= 1; SignX += 2)
|
||||||
|
{
|
||||||
|
for (int32 SignY = -1; SignY <= 1; SignY += 2)
|
||||||
|
{
|
||||||
|
const FVector Offset(SignX * HalfX, SignY * HalfY, 0.0f);
|
||||||
|
const float Depth = FVector::DotProduct(Offset, ViewDir); // 中心からの奥行きのずれ
|
||||||
|
const float Lateral = FMath::Abs(FVector::DotProduct(Offset, Right));
|
||||||
|
const float Vertical = FMath::Abs(FVector::DotProduct(Offset, Up));
|
||||||
|
|
||||||
|
// 条件: Lateral <= (Distance + Depth) * TanH, Vertical <= (Distance + Depth) * TanV
|
||||||
|
Distance = FMath::Max(Distance, Lateral / TanH - Depth);
|
||||||
|
Distance = FMath::Max(Distance, Vertical / TanV - Depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetActorLocationAndRotation(Center - ViewDir * Distance, Rotation);
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user