【虚幻引擎UE】UE4/UE5 基于2D屏幕坐标获取场景3D坐标 射线检测(蓝图/C++)

UE4/UE5 基于2D屏幕坐标获取场景3D坐标


一、射线检测

1)定义

射线检测(Ray Casting) 是一种计算机图形和计算机图形学中的基本技术,用于检测光线或射线是否与三维场景中的物体相交,以确定相交点的位置和其他相关信息。射线检测通常用于实现各种交互功能、渲染效果和物理模拟,包括但不限于鼠标拾取、光线追踪、碰撞检测和物体拾取等。

1)射线与3D场景中的物体交互的流程

步骤 描述
1 定义射线: 定义射线的起点和方向向量。
2 检测相交: 沿着射线的方向,从起点开始沿射线前进,检测射线是否与场景中的任何物体相交。 通常,这涉及到进行碰撞检测,以确定是否有物体与射线相交。
3 确定交点: 如果射线与物体相交,计算交点的位置。 交点通常以3D坐标的形式给出,表示射线与物体相交的点。
4 处理交互: 根据应用的需求,您可以在交互点上执行特定的操作,如选择物体、执行动作或渲染效果。
5 遍历所有可能的相交点: 射线检测通常可以返回多个相交点,因此可以考虑遍历所有可能的交点以处理多重相交。

2)射线检测蓝图函数

蓝图函数 描述
LineTraceByChannel 执行一条射线检测,检测与指定碰撞通道相交的物体。返回一个 Hit Result 结构。
SphereTraceByChannel 以球体的形状执行射线检测,检测球体与物体的碰撞。返回一个 Hit Result 结构。
LineTraceMultiByChannel 执行射线检测,检测与指定碰撞通道相交的所有物体。返回一个 Hit Results 数组。
SphereTraceMultiByChannel 以球体的形状执行射线检测,检测球体与多个物体的碰撞。返回一个 Hit Results 数组。
BoxTraceByChannel 执行射线检测,检测与指定碰撞通道相交的物体,使用盒子形状。返回一个 Hit Result 结构。
MultiSphereTraceByChannel 执行多个球体形状的射线检测,检测多个球体与物体的碰撞。返回一个 Hit Results 数组。
LineTraceForObjects 执行射线检测,检测与指定物体类型相交的物体。返回一个 Hit Result 结构。
SphereTraceForObjects 以球体的形状执行射线检测,检测与指定物体类型相交的物体。返回一个 Hit Result 结构。
BoxTraceForObjects 执行射线检测,检测与指定物体类型相交的物体,使用盒子形状。返回一个 Hit Result 结构。
MultiSphereTraceForObjects 执行多个球体形状的射线检测,检测与指定物体类型相交的物体。返回一个 Hit Results 数组。
CapsuleTraceByChannel 以胶囊体的形状执行射线检测,检测胶囊体与物体的碰撞。返回一个 Hit Result 结构。
CapsuleTraceForObjects 以胶囊体的形状执行射线检测,检测与指定物体类型相交的物体。返回一个 Hit Result 结构。

3)蓝图实现根据鼠标点击位置获取场景中的坐标值

4)根据相机中心点获取场景中的坐标值

需要获取到pawn里的相机。

5)射线检测相关C++函数

(仅列举linetrace系列其他大同小异)

  1. LineTraceSingleByChannel
    • 用于检测一条射线与第一个相交物体的碰撞。
    • 返回一个FHitResult结构,其中包含有关碰撞的信息,如碰撞点、碰撞法线和碰撞物体的引用。
cpp 复制代码
bool UWorld::LineTraceSingleByChannel(FHitResult& OutHit, const FVector Start, const FVector End, ECollisionChannel TraceChannel, const FCollisionQueryParams& Params)
  1. LineTraceMultiByChannel
    • 用于检测一条射线与多个相交物体的碰撞。
    • 返回一个TArray<FHitResult>,其中包含所有相交物体的碰撞信息。
cpp 复制代码
int32 UWorld::LineTraceMultiByChannel(TArray<FHitResult>& OutHits, const FVector Start, const FVector End, ECollisionChannel TraceChannel, const FCollisionQueryParams& Params)
  1. LineTraceSingleByObjectType
    • 类似于LineTraceSingleByChannel,但是使用物体类型(EObjectTypeQuery)而不是碰撞通道进行检测。
cpp 复制代码
bool UWorld::LineTraceSingleByObjectType(FHitResult& OutHit, const FVector Start, const FVector End, FObjectQueryParams ObjectQueryParams, const FCollisionQueryParams& Params)
  1. LineTraceMultiByObjectType
    • 类似于LineTraceMultiByChannel,但是使用物体类型(EObjectTypeQuery)而不是碰撞通道进行检测。
cpp 复制代码
int32 UWorld::LineTraceMultiByObjectType(TArray<FHitResult>& OutHits, const FVector Start, const FVector End, FObjectQueryParams ObjectQueryParams, const FCollisionQueryParams& Params)

6)C++实现手动创建射线检测

cpp 复制代码
FVector StartLocation;  // 射线的起点坐标
FVector ForwardVector;  // 射线的方向向量
FHitResult HitResult;  // 用于存储碰撞信息的变量

// 设置射线的起点坐标
StartLocation = PlayerCameraComponent->GetComponentLocation();  // PlayerCameraComponent是摄像机组件

// 设置射线的方向向量
ForwardVector = PlayerCameraComponent->GetForwardVector();  // 获取摄像机的前向向量

// 建立射线
FVector EndLocation = ((ForwardVector * RayLength) + StartLocation);  // 计算射线的终点坐标

// 进行射线检测
if (GetWorld()->LineTraceSingleByChannel(HitResult, StartLocation, EndLocation, ECC_Visibility))
{
    // 射线与物体相交,可以在HitResult中获取碰撞信息
    AActor* HitActor = HitResult.GetActor();
    FVector ImpactPoint = HitResult.ImpactPoint;
    // 进一步处理交互逻辑
}

PlayerCameraComponent:摄像机组件

LineTraceSingleByChannel:射线检测函数

HitResult:碰撞的物体和碰撞点

RayLength:射线的长度;

ECC_Visibility:射线检测所使用的碰撞通道

7)C++实现点击获取场景中的坐标值

cpp 复制代码
void AYourPlayerController::GetSceneLocationFromMouse()
{
    // 获取玩家控制器
    APlayerController* PlayerController = this;

    if (PlayerController)
    {
        // 获取鼠标点击位置
        FVector MouseLocation, MouseDirection;
        PlayerController->DeprojectMousePositionToWorld(MouseLocation, MouseDirection);

        // 创建射线,用于射线检测
        FHitResult HitResult;
        FCollisionQueryParams CollisionParams;

        // 执行射线检测
        if (GetWorld()->LineTraceSingleByChannel(HitResult, MouseLocation, MouseLocation + MouseDirection * YourRayLength, ECC_Visibility, CollisionParams))
        {
            // 获取射线与场景相交的位置
            FVector SceneLocation = HitResult.Location;

            // 打印结果
            UE_LOG(LogTemp, Warning, TEXT("Scene Location: %s"), *SceneLocation.ToString());
        }
    }
}

二、非射线检测的情况

1)根据相机当前位置获取中心点的世界坐标

cpp 复制代码
void AYourPlayerController::GetCameraCenterLocation()
{
    // 获取玩家控制器的视图控制器
    APlayerController* PlayerController = this;

    if (PlayerController)
    {
        // 获取相机组件
        UCameraComponent* CameraComponent = PlayerController->PlayerCameraManager->GetCameraComponent();

        if (CameraComponent)
        {
            // 获取相机位置
            FVector CameraLocation = CameraComponent->GetComponentLocation();

            // 获取相机旋转
            FRotator CameraRotation = CameraComponent->GetComponentRotation();

            // 计算相机中心点的位置(通常位于相机位置的前方,视角方向)
            FVector CameraForwardVector = CameraRotation.Vector();
            FVector CameraCenterLocation = CameraLocation + CameraForwardVector * YourDistance;  // 替换 YourDistance 为相机中心点到相机位置的距离

            // 将相机中心点的位置转换为场景中的坐标
            FVector WorldLocation = CameraCenterLocation;

            // 打印结果
            UE_LOG(LogTemp, Warning, TEXT("Camera Center Location: %s"), *WorldLocation.ToString());
        }
    }
}
相关推荐
Dawn·张7 小时前
UE小:在Unreal Engine 5中实现多层静态网格体遮挡拾取
ue5
lalapanda1 天前
UE5学习记录 part13
学习·ue5
lalapanda1 天前
UE5学习记录part12
学习·ue5
吴梓穆1 天前
UE5学习笔记 FPS游戏制作33 换子弹 动画事件
笔记·学习·ue4
吴梓穆1 天前
UE5学习笔记 FPS游戏制作31 显示计分板
笔记·学习·ue4
吴梓穆2 天前
UE5学习笔记 FPS游戏制作28 显式玩家子弹数
笔记·学习·ue4
吴梓穆2 天前
UE5学习笔记 FPS游戏制作33 游戏保存
笔记·学习·ue5
rrtt_23232 天前
UE5 + Rider + VsCode 接入腾讯的 Puerts 脚本
ue5·puerts·普洱
liangjiyucsdn3 天前
UE5新材质系统效果Demo展示
ue5
ue星空3 天前
UE5中开启ACES工作流程
ue5