chopper:目录​zhuanlan.zhihu.com

本节将描述两种射线与球体的相交测试方法,方法一是采用参数方程求解的方法,可以计算出直线、射线、线段与球的交点,方法二在Akenine-Möller等[1]中有描述,只涉及射线与球的相交测试,采用几何关系来优化测试。此外,对二维空间下,射线与圆的相交测试,也可以采用本节介绍的两种方法,由于维度更小,所以更加简单,这里就不再赘述,最后提供描述算法的源码实现。

文章目录:

  • 参数方程法
  • 优化法
  • 源码实现
  • 参考

射线

与以
为球心、
为半径的球体的相交测试,不需要保证
是单位长度。

参数方程法

球面可以用参数方程表示为

现在考虑直线与球面的相交,把直线的参数方程代入等式(1)中,得

这是类似于

的一元二次方程,直接求解该方程的解,得

,则解可以分为三种情况: + i. 若
,方程无解,直线与球体不相交; + ii. 若
,方程有一个解,直线与球体相切; + iii. 若
,方程有两个解,直线与球体相交。
图1. 直线与球相交的三种情况

直线与球体相交的三种情况,如图1所示。图(a)就是第i种情况,两者不相交;图(b)就是第ii种情况,相切于一点;图(c)就是第iii种情况,相交于两点。算法的伪码如下所示:

直线

与以
为球心、
为半径的球体的相交测试,
可以是非单位长度,若相交,求计算出所有交点

return (交点的个数)
1.

;

2.

;

3.

;

4. if

, then

5.     return 0;
6. else if

, then

7.     

;

8.     

;

9.     

;

10.     return 1;
11. else
12.     

;

13.     

;

14.     

;

15.     

;

16.     return 2;
17. end if;

对于射线与球体的相交测试中,需要保证

的值限定的区间范围
内;对于线段与球体的相交测试中,需要保证
的值限定的区间范围
内。

算法的C++实现代码如下所示:

优化法

设射线的参数方程为

,其中
是单位长度。如图2(a)所示,计算出从射线原点出发到球体中心的向量
,计算出该向量的长度
,若
,那么说明射线的原点在球体内部,一定与球体相交,如图2(c)所示,若只是想判断它们是否相交,算法至此就可以结束了。否则,计算向量
沿着
方向的投影:
,若
,说明球体在射线原点的后面,且射线的原点在球体外,因此可以判定射线与球体一定不相交,完成第一次排除测试,如图2(b)所示。否则,利用勾股定理,计算出球心与投影之间距离的平方:
,若
,则可以判定射线与球体一定不相交,完成第二次排除测试。如果射线和球体经过两次排除测试,则就可以判定它们一定相交。如果只希望判定它们是否相交,算法至此就可以结束了。
图2. 射线与球体相交测试的优化方法

接下来,计算射线与球体的交点,计算出距离的平方,

,因为
,所以计算出
的值。相交点与射线原点之间的距离为
,求第一个相交点,若
,说明射线原点在球体外,取
,否则取
,最后把
值代入射线的参数方程中,就求出第一个相交点。

射线与球体相交测试并计算交点的算法伪码如下所示:

射线

与以
为球心、
为半径的球体的相交测试,
是单位长度,若相交,计算出第一个交点

return ({DISJOINT, INTERSECTING})
1.

;

2.

;

3.

4. if

and
, then

5.     return DISJOINT;
6. end if;
7.

;

8. if

, then

9.     return DISJOINT;
10. end if;
11.

;

12. if

, then

13.     

;

14. else
15.     

;

16. end if;
17.

;

18. return INTERSECTING;

若不需要计算射线与球体的交点,只需要判断它们是否相交,那么伪码如下所示:

射线

与以
为球心、
为半径的球体的相交测试,
是单位长度,不需要计算交点

return ({DISJOINT, INTERSECTING})
1.

;

2.

;

3. if

, then

4.     return INTERSECTING;
5. end if;
6.

;

7. if

, then

8.     return DISJOINT;
9. end if;
10.

;

11. if

, then

12.     return DISJOINT;
13. end if;
14. return INTERSECTING;

与参数方程法相比,具有相同的运算次数,但最大的不同是该方法较早地进行筛除计算,从而使这个算法总的开销要低一些。

源码实现

基础库源码链接,参见这里,下面是前面所描述的算法的实现。

#include "SrGeometricTools.h"
#include "SrDataType.h"#include <stdio.h>
#include <time.h>namespace {/************************************************************************
description    采用参数方程法和优化法,实现射线与球体的相交测试。
****************************************************************************//**
brief 3D sphere class.This is a 3D sphere class with public data members.
It includes center and radius.
*/class SrSphere3D{public:/**brief Default constructor. Set center to (0,0) and radius to 0.*/SrSphere3D(){mCenter.set(0, 0, 0);mRadius = -1.0;}/**brief The circle is initialized by center and radius.*/SrSphere3D(const SrPoint3D& ct, SrReal rd){mCenter = ct;mRadius = rd;}public:SrPoint3D   mCenter;SrReal      mRadius;};/**brief 3D ray class.This is a 3D ray class with public data members.The ray is parameterized as X(t) = P+t*d,in which P is the 'base' data,d is the 'direction' data,t>=0.the 'direction' is unit length.*/class SrRay3D{public:/**brief Default constructor, base and direction is set to (0,0).*/SrRay3D(){mBase.set(0, 0, 0);mDirection.set(0, 0, 0);}/**brief The line is initialized by two points.The point p1 is the endpoint of the ray.*/SrRay3D(const SrPoint3D& p1, const SrPoint3D& p2){mBase = p1;mDirection = p2 - p1;mDirection.normalize();}/**brief  The ray is valid if the direction of the line is unit.*/bool isValid()const{if (EQUAL(mDirection.magnitudeSquared(), 1.0))return true;return false;}public:SrPoint3D   mBase;SrVector3D  mDirection;};/*brief  采用参数方程法,实现射线与球体的相交测试。param[out] result  射线可以用参数方程P+tD表示,返回第一个相切点的t值。return true    若射线与球体相交或者相切;false   若射线与球体分离(无交点)。*/bool RayHitTestSphere_Parameter(const SrRay3D& ray, const SrSphere3D& sphere, SrReal& result){SrVector3D e = ray.mBase - sphere.mCenter;SrReal b = e.dot(ray.mDirection), c = e.dot(e) - sphere.mRadius*sphere.mRadius;SrReal delta = b * b - c;if (LESS(delta, 0))return false;else if (EQUAL(delta, 0)){if (LESS(-b, 0))return false;result = -b;return true;}else{SrReal d = sqrt(delta);SrReal t1 = -b - d, t2 = -b + d;if (LESS(t2, 0))return false;else if (LESS(t1, 0))result = t2;elseresult = t1;return true;}return true;}/*brief  采用优化法,实现射线与球体的相交测试。param[out] result  射线可以用参数方程P+tD表示,返回第一个相切点的t值。return true    若射线与球体相交或者相切;false   若射线与球体分离(无交点)。*/bool RayHitTestSphere_Optimized(const SrRay3D& ray, const SrSphere3D& sphere, SrReal& result){SrVector3D l = sphere.mCenter - ray.mBase;SrReal s = l.dot(ray.mDirection);SrReal squaredL = l.dot(l);SrReal squaredRadius = sphere.mRadius * sphere.mRadius;if (LESS(s, 0) && GREATER(squaredL, squaredRadius))return false;SrReal squaredM = squaredL - s * s;if (GREATER(squaredM, squaredRadius))return false;SrReal q = sqrt(squaredRadius - squaredM);if (squaredL > squaredRadius)result = s - q;elseresult = s + q;return true;}/*brief 随机生成射线数据,测试两种相交测试方法的正确性,并测试两种方法的CPU时钟开销。*/void Test_RayHitTestSphere(){int numRay = 100000;SrRay3D* ray = new SrRay3D[numRay];//确定测试球体SrSphere3D sphere(SrPoint3D(1000, 1000, 1000), 1000);int i;SrPoint3D p0, p1;//随机生成测试的射线for (i = 0; i < numRay; i++){do{p0.x = rand() % 2000;p0.y = rand() % 2000;p0.z = rand() % 2000;p1.x = rand() % 2000;p1.y = rand() % 2000;p1.z = rand() % 2000;ray[i] = SrRay3D(p0, p1);} while (!ray[i].isValid());}SrReal t0, t1;bool ret0, ret1;//测试算法的正确性for (i = 0; i < numRay; i++){ret0 = RayHitTestSphere_Parameter(ray[i], sphere, t0);ret1 = RayHitTestSphere_Optimized(ray[i], sphere, t1);ASSERT(ret0 == ret1);//printf("%f,%fn",t0, t1);//ASSERT(EQUAL(t0,t1));}//参数方程法,消耗时间的统计double mTime = clock();for (i = 0; i < numRay; i++){ret0 = RayHitTestSphere_Parameter(ray[i], sphere, t0);}mTime = (clock() - mTime) / CLOCKS_PER_SEC;printf("时间:%fn", mTime);//优化法,消耗时间的统计mTime = clock();for (i = 0; i < numRay; i++){ret0 = RayHitTestSphere_Optimized(ray[i], sphere, t0);}mTime = (clock() - mTime) / CLOCKS_PER_SEC;printf("时间:%fn", mTime);}
}int main()
{Test_RayHitTestSphere();return 0;
}

参考

[1] Tomas Akenine-Möller, Eric Haines, and Naty Hoffman. Real-time rendering, second edition. AK, 2002.

c++中射线表示_射线与球的相交测试相关推荐

  1. 土木搬砖工图形学学习之路——射线与包围盒的相交测试

    本人土木转计算机,目前刚刚开始研究生生涯.最近喜欢上了三维计算机图形学,被射线与包围盒的相交测试函数卡了许久,以下分享一些个人的学习理解. 一.结构体定义 包围盒定义为三维空间中一个立方体,其六个面分 ...

  2. c++中射线表示_干货中的干货 万人收藏的小学数学知识点大全(下)基本概念汇总...

    第二章 度量衡 长度 (一) 什么是长度 长度是一维空间的度量. (二) 长度常用单位 公里(km) 米(m) 分米(dm) 厘米(cm) 毫米(mm) 微米(um) (三) 单位之间的换算 1毫米 ...

  3. matlab中表示拉普拉斯分布_双导体球在匀强外电场中的空间电场分布

    导体球或球壳在匀强外电场中的场强分布是电动力学中的经典题目,也是大家所熟悉的题目,但均匀电场中出现两个导体球或球壳(二聚体)时的场强却少有讨论.两导体球电极化所引起的导体球间电磁场的局域增强是表面等离 ...

  4. python包的中 _init _.py文件介绍

    python包的中 _init _.py文件介绍 我们新建python包时常常会看到一个__init _.py文件. 作用介绍: ​ 一:这个文件是属于python包的,这个文件用作于标识python ...

  5. sql错误索引中丢失_收集,汇总和分析丢失SQL Server索引统计信息

    sql错误索引中丢失 描述 (Description) Indexing is key to efficient query execution. Determining what indexes a ...

  6. python命名规则数字开头的成语_浅谈Python中带_的变量或函数命名

    搜索热词 Python 的代码风格由 PEP 8 描述.这个文档描述了 Python 编程风格的方方面面.在遵守这个文档的条件下,不同程序员编写的 Python 代码可以保持最大程度的相似风格.这样就 ...

  7. 纳米二氧化硅修饰中孔ZSM-5沸石微球/含钆介孔二氧化硅海藻酸钠纳米微球

    纳米二氧化硅修饰中孔ZSM-5沸石微球的制备: 其特征在于是一种具有晶内和晶间两类中孔的微球,该微球是由具有晶内中孔的纳米沸石晶粒自聚而形成的,微球的直径为4-8μm,纳米沸石晶粒粒径为15-50nm ...

  8. 用 java实现双色球号码生成系统;(在装满33个红色球池中连续抽取6个红球; 在一个装满16颗球的蓝色球池中抽取1个蓝球。)

    用实际抓球实现(模仿现实变量) public class TestLottery1 {/*双色球号码生成算法一:模仿现实情况,在一个装满33个球的球池中连续抽取6个红球:在一个装满16颗球的球池中抽取 ...

  9. 管理系统中计算机应用课件,管理系统中计算机应用_第三章课件.ppt

    <管理系统中计算机应用_第三章课件.ppt>由会员分享,提供在线免费全文阅读可下载,此文档格式为ppt,更多相关<管理系统中计算机应用_第三章课件.ppt>文档请在天天文库搜索 ...

最新文章

  1. 图片上传(加水印、缩略图、远程保存)的简单例子
  2. TLS与openssl学习总结(三)-实操篇
  3. toeplitz--生成托普利兹矩阵
  4. javascript 模板引擎基本原理
  5. react java编程_快速上手React编程 PDF 下载
  6. 20180802总结
  7. 2017.9.13 序列维护 思考记录
  8. 《数学之美》—贾里尼克和现代语言处理
  9. Xcode 9: An error occurred uploading to the iTunes Store. iTunes Store Operation Failed
  10. DRF使用超链接API实现真正RESTful
  11. docker 配置 CA验证
  12. 用matlab画散点图并用光滑曲线连接(样条插值)
  13. C语言正弦和余弦的值
  14. AI前沿论坛会议—文字智能和游戏智能总结篇
  15. 免费期刊下载——超星发现
  16. 2021中国市场十大IT热点
  17. 时间戳指什么呢?(通俗易懂的简介大白话)
  18. 电商后台系统产品逻辑全解析
  19. linux全角半角切换,教您输入法全角和半角怎么切换
  20. 大数据处理的关键技术有哪些?

热门文章

  1. 深度解析DDD中台和微服务设计
  2. 瑞幸咖啡股价再创新低,App 反冲 TOP 1
  3. 什么是Apache Spark?这篇文章带你从零基础学起
  4. CANOpen报文类型
  5. 看了5种分布式事务方案,最终选择了Seata,真香!
  6. 一程序员被判 9 个月:因薪酬等问题离职,rm -f * 删库,瘫痪 6 个小时
  7. 任正非:再见,荣耀!从此以后便是对手!
  8. 天才程序员的传奇人生:项目被总统抢走,在瞄准镜下写完代码后被捕入狱
  9. 字节跳动的敌人只有时间
  10. 女神节快乐!世界上第一位程序员就是女神