当前位置: 首页 > news >正文

【UE5 C++】判断两点连线是否穿过球体

目录

前言

方法一 

原理

代码

测试

结果

方法二

原理

一、检查连线与球体的相交情况

二、检查距离与球体半径的关系

三、检查连线与球体的相交

代码


前言

       通过数学原理判断空间中任意两点的连线是否穿过球体,再通过射线检测检验算法的正确性。

方法一 

原理

(1)设球体球心的坐标为O(C_{x},C_{y},C_{z}) ,半径为r;

(2)设线段AB中A点的坐标为A(x_{1},y_{1},z_{1}),B点的坐标为B(x_{2},y_{2},z_{2})

(3)计算\underset{OA}{\rightarrow}\underset{OB}{\rightarrow}\underset{AB}{\rightarrow}

(4)计算点O到 线段AB的最短距离d

d=\frac{|\underset{OA}{\rightarrow}\times \underset{AB}{\rightarrow}|}{|\underset{AB}{\rightarrow}|}

(5) 如果d\leq r,则线段AB穿过球体;如果d> r,则线段AB不穿过球体。

代码

        定义一个函数“IsCrossSphere”来判断线段AB是否穿过球体,函数需要传入点A、B的坐标以及球心坐标和球体半径。

再定义一个结构体作为函数返回值

函数“IsCrossSphere”的实现如下

头文件:

// Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "LineIsCrossSphere.generated.h"USTRUCT(BlueprintType)
struct FStruct_Result_IsLineCrossSphere
{GENERATED_BODY();
public:UPROPERTY(BlueprintReadWrite)float distanceOfLineAndSphereCenter;UPROPERTY(BlueprintReadWrite)bool isCrossSphere;
};UCLASS()
class STUDY_API ALineIsCrossSphere : public AActor
{GENERATED_BODY()public:	// Sets default values for this actor's propertiesALineIsCrossSphere();protected:// Called when the game starts or when spawnedvirtual void BeginPlay() override;UFUNCTION(BlueprintCallable)FStruct_Result_IsLineCrossSphere IsCrossSphere(FVector pointA, FVector pointB, FVector sphereOrginPoint, float sphereRadius);   //计算线段AB到球心的距离并判断AB是否穿过球体public:	// Called every framevirtual void Tick(float DeltaTime) override;};

源文件:

// Fill out your copyright notice in the Description page of Project Settings.#include "Test/LineIsCrossSphere.h"// Sets default values
ALineIsCrossSphere::ALineIsCrossSphere()
{// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.PrimaryActorTick.bCanEverTick = true;}// Called when the game starts or when spawned
void ALineIsCrossSphere::BeginPlay()
{Super::BeginPlay();}FStruct_Result_IsLineCrossSphere ALineIsCrossSphere::IsCrossSphere(FVector pointA, FVector pointB, FVector sphereOrginPoint, float sphereRadius)
{bool isCrossSphere;FVector OA = pointA - sphereOrginPoint;FVector OB = pointB - sphereOrginPoint;FVector AB = OB - OA;FVector n = OA.Cross(AB);float D = n.Size() / AB.Size();if (D > sphereRadius){isCrossSphere =  false;}else{isCrossSphere =  true;}FStruct_Result_IsLineCrossSphere result;result.isCrossSphere = isCrossSphere;result.distanceOfLineAndSphereCenter = D;return result;
}// Called every frame
void ALineIsCrossSphere::Tick(float DeltaTime)
{Super::Tick(DeltaTime);}

测试

        在Tick中每帧去发射射线检测并调用函数 “IsCrossSphere”,通过观察射线碰撞结果以及函数 “IsCrossSphere”的打印是否相等来判断算法是否有误。(这里设置球体半径固定为50,球体坐标为(0,0,0))

结果

        可以看到不论是线段在球体表面,穿过球体,还是在球体外,函数 “IsCrossSphere”与射线检测的结果都是一致的。

方法二

原理

一、检查连线与球体的相交情况

        使用距离公式计算点 A到球体中心O 的距离d_{A},以及点 B到地球中心O 的距离d_{B},设点AA(x_{1},y_{1},z_{1}),点BB(x_{2},y_{2},z_{2})

d_{A}=\sqrt{(x_{1}-C_{x})^{2}+(y_{1}-C_{y})^{2}+(z_{1}-C_{z})^{2}}

d_{B}=\sqrt{(x_{2}-C_{x})^{2}+(y_{2}-C_{y})^{2}+(z_{2}-C_{z})^{2}}

二、检查距离与球体半径的关系

        如果 d_{A}\leq R 且 d_{B}\leq R,则两点都在球体内部,它们的连线显然穿过球体;

        如果 d_{A}> R 且 d_{B}> R,则两点都在球体外部,需要进一步检查它们的连线是否与球体相交。

三、检查连线与球体的相交

        当两点都在球体外部时,我们可以计算直线 AB 的参数方程,并尝试找到与球体表面(即半径为 R 的球体)的交点。将直线的参数方程代入球体的方程,并解出一个关于参数的二次方程。如果这个二次方程有实数解,并且解对应的参数值在 0 和 1 之间(对于参数化的线段 AB),则连线与球体相交。

 (1)表示直线参数方程

        对于线段AB的参数方程可以表示为

r(t)=(1-t)A+tB

r(t)=((1-t)x_{1}+tx_{2},(1-t)y_{1}+ty_{2},(1-t)z_{1}+tz_{2}) 

         其中t是参数,0\leqslant t\leqslant 1表示线段AB上的点

(2)表示球体方程

        设球体球心的坐标为O(C_{x},C_{y},C_{z}) ,半径为R,则球体方程可表示为

(x-C_{x})^{2}+(y-C_{y})^{2}+(z-C_{z})^{2}=R^{2}

(3)将直线的参数方程代入球体的方程中,得到一个关于t的二次方程

 

 展开并整理后,可得到一个标准的二次方程形式:at^{2}+bt+c=0

(4)使用求根公式可以得到二次方程的解

(5)如果二次方程没有实数解(\Delta < 0),则直线不与球体相交;

         如果二次方程有一个实数解,并且解在 0≤t≤1 的范围内,则线段 AB 与球体相交于一点;

        如果二次方程有两个不同的实数解,并且至少有一个解在 0≤t≤1 的范围内,则直线段 AB 与球体相交于两点(即线段穿过球体)。

代码

bool ALineIsCrossSphere::IsCrossSphere2(FVector pointA, FVector pointB, FVector sphereOrginPoint, float sphereRadius)
{float D_A = sqrt(pow(pointA.X - sphereOrginPoint.X, 2) + pow(pointA.Y - sphereOrginPoint.Y, 2) + pow(pointA.Z - sphereOrginPoint.Z, 2));  //计算点A到球体中心的距离float D_B = sqrt(pow(pointB.X - sphereOrginPoint.X, 2) + pow(pointB.Y - sphereOrginPoint.Y, 2) + pow(pointB.Z - sphereOrginPoint.Z, 2));  //计算点B到球体中心的距离if (D_A <= sphereRadius && D_B <= sphereRadius)  //两点都在球体内部,它们的连线显然穿过球体{return true;}else if (D_A > sphereRadius && D_B > sphereRadius)  //两点都在球体外部{//将直线的参数方程代入球体的方程,得到标准二次方程的a、b、cfloat a = pow(pointB.X - pointA.X, 2) + pow(pointB.Y - pointA.Y, 2) + pow(pointB.Z - pointA.Z, 2);float b = 2 * ((pointB.X - pointA.X) * (pointA.X - sphereOrginPoint.X) + (pointB.Y - pointA.Y) * (pointA.Y - sphereOrginPoint.Y) + (pointB.Z - pointA.Z) * (pointA.Z - sphereOrginPoint.Z));float c = pow(pointA.X - sphereOrginPoint.X, 2) + pow(pointA.Y - sphereOrginPoint.Y, 2) + pow(pointA.Z - sphereOrginPoint.Z, 2) - pow(sphereRadius, 2);float discriminant = b * b - 4 * a * c;if (discriminant > 0.0f)  //△>0{// 有两个不同的实数解float t1 = (-1*b + sqrt(pow(b, 2) - 4 * a * c)) / (2 * a);float t2 = (-1*b - sqrt(pow(b, 2) - 4 * a * c)) / (2 * a);if ((0 <= t1 && t1 <= 1) || (0 <= t2 && t2 <= 1)){return true;  //至少有一个解在0~1,则线段 AB 与球体相交于两点}else {return false;  //直线与球体在无限远处相交,即线段没有穿过球体}}else if (discriminant == 0.0f)  //△=0{// 有两个相等的实数解(或说是一个重根)float t = (-1 * b) / (2 * a);if (t >= 0 && t <= 1){return true;  //直线段 AB 与球体相交于一点}else{return false; //虽然直线在无限延伸的情况下会与球体相交,但交点并不在连接点A和点B的线段上,因此没有相交}}else  //△<0{// 没有实数解,直线不与球体相交return false;}}else  //一点在球体内部,另一点在球体外部,则它们的连线一定穿过球体{return true;}
}

相关文章:

【UE5 C++】判断两点连线是否穿过球体

目录 前言 方法一 原理 代码 测试 结果 方法二 原理 一、检查连线与球体的相交情况 二、检查距离与球体半径的关系 三、检查连线与球体的相交 代码 前言 通过数学原理判断空间中任意两点的连线是否穿过球体&#xff0c;再通过射线检测检验算法的正确性。 方法一 …...

【Blender】如何创建空心管道

步骤 1&#xff1a;创建一个圆柱体 添加圆柱体&#xff1a; 在 Object Mode 下按 Shift A > Mesh > Cylinder。 步骤 2&#xff1a;制作空心效果 进入编辑模式&#xff1a; 选中圆柱体&#xff0c;按 Tab 进入 Edit Mode。 删除顶部和底部面&#xff1a; 按 3 进入面选…...

ChromeBook11 HP G7EE 刷入Ubuntu的记录

设置开发模式-> 拆电池(解锁)-> 刷入bios ->使用u盘刷入系统。 下面是详细过程&#xff0c;除了拆机有点紧&#xff0c;没有难度(我不负责&#xff5e; 其实我试了好几次其他系统的&#xff0c;先进了pe&#xff0c;pe没问题(音频x)&#xff0c;有一个win10的u盘(几个…...

16asm - 汇编介绍 和 debug使用

文章目录 前言硬件运行机制微机系统硬件组成计算机系统组成8086cpu组织架构dosbox安装配置debug debug使用R命令D命令E命令U命令T命令A命令标志寄存器 总结 前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;今天给大家讲解 十六位汇编 和 debug调试器的使用 硬件运行…...

初识QT第一天

思维导图 利用Qt尝试做出原神登陆界面 import sys from PyQt6.QtGui import QIcon, QPixmap, QMovie from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QLineEdit# 封装原神窗口类 class Genshin(QWidget):# 构造函数def __init__(self):# 初始化父类…...

ChatGPT科研应用、论文写作、课题申报、数据分析与AI绘图

随着人工智能技术的飞速发展&#xff0c;ChatGPT等先进语言模型正深刻改变着科研工作的面貌。从科研灵感的激发、论文的高效撰写&#xff0c;到课题的成功申报&#xff0c;乃至复杂数据的深度分析与可视化呈现&#xff0c;AI技术均展现出前所未有的潜力。其实众多科研前沿工作者…...

原子类、AtomicLong、AtomicReference、AtomicIntegerFieldUpdater、LongAdder

原子类 JDK提供的原子类&#xff0c;即Atomic*类有很多&#xff0c;大体可做如下分类&#xff1a; 形式类别举例Atomic*基本类型原子类AtomicInteger、AtomicLong、AtomicBooleanAtomic*Array数组类型原子类AtomicIntegerArray、AtomicLongArray、AtomicReferenceArrayAtomic…...

c语言——数组名该如何理解呢?

一般情况下&#xff0c;数组名表示首元素地址&#xff0c;以下2种除外&#xff1a; ①、sizeof(数组名) 表示整个数组 ※只有数组名的情况 sizeof&#xff08;数组名i&#xff09; 就不能表示整个数组 ②、&数组名 表示整个数组&#xff0c;取的是整个数…...

Linux学习笔记13 系统进程管理

前文 Linux学习笔记10 系统启动初始化&#xff0c;服务和进程管理&#xff08;上&#xff09;-CSDN博客 Linux学习笔记11 系统启动初始化&#xff0c;服务和进程管理&#xff08;下&#xff09;-CSDN博客 Linux学习笔记12 systemd的其他命令-CSDN博客 之前学习了怎么使用sy…...

Spring Boot 项目集成camunda流程引擎

Spring Boot 项目集成camunda流程引擎 camunda地址 camunda中文地址 使用camunda开源工作流引擎有&#xff1a;通过docker运行、使用springboot集成、部署camunda发行包、基于源代码编译运行等多种方式。 文本重点介绍如何在Spring Boot应用程序中如何集成Camunda Platform开…...

2024.12.2工作复盘

1.今天学了什么&#xff1f; 简单的写了一篇博客&#xff0c;是关于参数校验的问题&#xff0c;参数校验&#xff0c;一个是前后端校验到底一不一致&#xff0c;一个是绕过前端校验&#xff0c;看后台的逻辑到底能不能校验住。 2.今天解决了什么问题&#xff1f; 3.今天完成…...

Hot100 - 二叉树的中序遍历

Hot100 - 二叉树的中序遍历 最佳思路&#xff1a; 中序遍历的顺序是&#xff1a;左子树 -> 根节点 -> 右子树。为了实现这个顺序&#xff0c;我们可以利用栈来模拟递归过程&#xff0c;从而避免栈溢出的问题。在遍历过程中&#xff0c;始终向左子树深入&#xff0c;直到…...

docker build ubuntu ssh

dockerfile 构建镜像 为了使用Dockerfile构建Docker镜像&#xff0c;请遵循以下步骤&#xff1a; 创建一个名为Dockerfile的文件&#xff0c;并在其中定义镜像的构建指令。 FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/ubuntu:24.04# 安装openssh-server和pas…...

三维路径规划|基于黑翅鸢BKA优化算法的三维路径规划Matlab程序

三维路径规划|基于黑翅鸢BKA优化算法的三维路径规划Matlab程序 文章目录 前言三维路径规划|基于黑翅鸢BKA优化算法的三维路径规划Matlab程序基于黑翅鸢BKA优化算法的三维路径规划一、研究基本原理二、黑翅鸢BKA优化算法的基本步骤&#xff1a;三、详细流程四、总结 二、实验结果…...

day01(Linux底层)基础知识

目录 导学 基础知识 1、Bootloader是什么 2、Bootloader的基本作用 3、入式中常见的Bootloader有哪些 4、Linux系统移植为什么要使用bootloader 5、uboot和Bootloader之间的关系 6.Uboot的获取 7、uboot版本命名 8、uboot版本选择 9、uboot的特点 10.Uboot使用 导学…...

flink学习(13)—— 重试机制和维表join

重试机制 当任务出现异常的时候&#xff0c;会直接停止任务——解决方式&#xff0c;重试机制 1、设置checkpoint后&#xff0c;会给任务一个重启策略——无限重启 2、可以手动设置任务的重启策略 代码设置 //开启checkpoint后&#xff0c;默认是无限重启&#xff0c;可以…...

第三方Cookie的消亡与Google服务器端标记的崛起

随着互联网用户对隐私保护的关注日益增强&#xff0c;各大浏览器正在逐步淘汰第三方Cookie。这一变革深刻影响了广告商和数字营销人员的用户跟踪和数据分析方式。然而&#xff0c;Google推出的服务器端标记技术为这一挑战提供了新的解决方案。 什么是第三方Cookie&#xff1f; …...

微信小程序——文档下载功能分享(含代码)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

Burp Suite 全面解析:开启你的 Web 安全测试之旅

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…...

Oracle DataGuard 主备正常切换 (Switchover)

前言 众所周知&#xff0c;DataGuard 的切换分为两种情况&#xff1a; 系统正常情况下的切换&#xff1a;这种方式称为 switchover&#xff0c;是无损切换&#xff0c;不会丢失数据。灾难情况下的切换&#xff1a;这种情况下一般主库已经启动不起来了&#xff0c;称为 failov…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动

一、前言说明 在2011版本的gb28181协议中&#xff0c;拉取视频流只要求udp方式&#xff0c;从2016开始要求新增支持tcp被动和tcp主动两种方式&#xff0c;udp理论上会丢包的&#xff0c;所以实际使用过程可能会出现画面花屏的情况&#xff0c;而tcp肯定不丢包&#xff0c;起码…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…...

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南

在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...