Use CameraComponent for view point and gaze target (VR/FPS compatibility)

- InteractionComponent: GetPawnViewPoint() now prefers UCameraComponent
  over PlayerController::GetPlayerViewPoint() — fixes agent selection
  in VR where the pawn root stays at spawn while the HMD moves freely
- GazeComponent: ResolveTargetPosition() uses camera first for locally
  controlled pawns (VR HMD / FPS eye position), falls back to bone
  chain for NPCs and remote players in multiplayer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
j.foucher 2026-03-05 14:13:09 +01:00
parent e5f40c65ec
commit 8ad66ae4d5
2 changed files with 63 additions and 41 deletions

View File

@ -58,25 +58,41 @@ static FVector ResolveTargetPosition(const AActor* Target, bool bAutoEyes,
{
if (!Target) return FVector::ZeroVector;
if (bAutoEyes)
if (!bAutoEyes)
{
// Try to find a Face mesh with eye bones on the target
// Manual mode: actor origin + user-defined offset
return Target->GetActorLocation() + ManualOffset;
}
// For locally controlled pawns (VR/FPS player), prefer the CameraComponent.
// In VR the pawn's skeletal mesh may stay at the spawn point while the HMD
// moves freely — using eye bones would make the agent look at the floor.
if (const APawn* Pawn = Cast<APawn>(Target))
{
if (Pawn->IsLocallyControlled())
{
if (const UCameraComponent* Cam =
const_cast<AActor*>(Target)->FindComponentByClass<UCameraComponent>())
{
return Cam->GetComponentLocation();
}
}
}
// For other targets (NPCs, remote players): bone chain.
TArray<USkeletalMeshComponent*> SkelMeshes;
const_cast<AActor*>(Target)->GetComponents<USkeletalMeshComponent>(SkelMeshes);
for (const USkeletalMeshComponent* SMC : SkelMeshes)
{
if (!SMC) continue;
if (SMC->DoesSocketExist(TargetEyeBoneL) && SMC->DoesSocketExist(TargetEyeBoneR))
{
// Midpoint between both eye bones
return (SMC->GetSocketLocation(TargetEyeBoneL)
+ SMC->GetSocketLocation(TargetEyeBoneR)) * 0.5f;
}
}
// Fallback: head bone on any mesh
for (const USkeletalMeshComponent* SMC : SkelMeshes)
{
if (!SMC) continue;
@ -86,22 +102,17 @@ static FVector ResolveTargetPosition(const AActor* Target, bool bAutoEyes,
}
}
// Fallback: CameraComponent — the canonical eye position for
// first-person pawns and any actor with an active camera.
// CameraComponent fallback for non-locally-controlled targets that have one.
if (const UCameraComponent* Cam =
const_cast<AActor*>(Target)->FindComponentByClass<UCameraComponent>())
{
return Cam->GetComponentLocation();
}
// Final fallback: actor origin + height offset
// Final fallback: actor origin + height offset.
return Target->GetActorLocation() + FVector(0.0f, 0.0f, FallbackHeight);
}
// Manual mode: actor origin + user-defined offset
return Target->GetActorLocation() + ManualOffset;
}
// ─────────────────────────────────────────────────────────────────────────────
// Construction
// ─────────────────────────────────────────────────────────────────────────────

View File

@ -9,6 +9,7 @@
#include "GameFramework/Pawn.h"
#include "GameFramework/PlayerController.h"
#include "Camera/PlayerCameraManager.h"
#include "Camera/CameraComponent.h"
#include "TimerManager.h"
#include "Net/UnrealNetwork.h"
@ -434,7 +435,17 @@ void UPS_AI_ConvAgent_InteractionComponent::GetPawnViewPoint(FVector& OutLocatio
return;
}
// Try to get the player controller's camera view (most accurate for first/third person).
// Prefer the CameraComponent directly — most reliable for VR (HMD) and FPS (eye level).
// In VR the pawn's actor location stays at the spawn point while the HMD moves freely,
// so GetPlayerViewPoint() may not reflect the actual head position.
if (UCameraComponent* Cam = Owner->FindComponentByClass<UCameraComponent>())
{
OutLocation = Cam->GetComponentLocation();
OutDirection = Cam->GetForwardVector();
return;
}
// Fallback: PlayerController view point (camera manager pipeline).
if (APawn* Pawn = Cast<APawn>(Owner))
{
if (APlayerController* PC = Cast<APlayerController>(Pawn->GetController()))
@ -446,7 +457,7 @@ void UPS_AI_ConvAgent_InteractionComponent::GetPawnViewPoint(FVector& OutLocatio
}
}
// Fallback: use actor location and forward.
// Final fallback: actor transform.
OutLocation = Owner->GetActorLocation();
OutDirection = Owner->GetActorForwardVector();
}