c++中射线表示_射线与球的相交测试
![](/assets/blank.gif)
chopper:目录zhuanlan.zhihu.com
![](/assets/blank.gif)
本节将描述两种射线与球体的相交测试方法,方法一是采用参数方程求解的方法,可以计算出直线、射线、线段与球的交点,方法二在Akenine-Möller等[1]中有描述,只涉及射线与球的相交测试,采用几何关系来优化测试。此外,对二维空间下,射线与圆的相交测试,也可以采用本节介绍的两种方法,由于维度更小,所以更加简单,这里就不再赘述,最后提供描述算法的源码实现。
文章目录:
- 参数方程法
- 优化法
- 源码实现
- 参考
射线
参数方程法
球面可以用参数方程表示为
现在考虑直线与球面的相交,把直线的参数方程代入等式(1)中,得
这是类似于
令
![](/assets/blank.gif)
直线与球体相交的三种情况,如图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++实现代码如下所示:
优化法
设射线的参数方程为
![](/assets/blank.gif)
接下来,计算射线与球体的交点,计算出距离的平方,
射线与球体相交测试并计算交点的算法伪码如下所示:
射线
与以
为球心、
为半径的球体的相交测试,
是单位长度,若相交,计算出第一个交点
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++中射线表示_射线与球的相交测试相关推荐
- 土木搬砖工图形学学习之路——射线与包围盒的相交测试
本人土木转计算机,目前刚刚开始研究生生涯.最近喜欢上了三维计算机图形学,被射线与包围盒的相交测试函数卡了许久,以下分享一些个人的学习理解. 一.结构体定义 包围盒定义为三维空间中一个立方体,其六个面分 ...
- c++中射线表示_干货中的干货 万人收藏的小学数学知识点大全(下)基本概念汇总...
第二章 度量衡 长度 (一) 什么是长度 长度是一维空间的度量. (二) 长度常用单位 公里(km) 米(m) 分米(dm) 厘米(cm) 毫米(mm) 微米(um) (三) 单位之间的换算 1毫米 ...
- matlab中表示拉普拉斯分布_双导体球在匀强外电场中的空间电场分布
导体球或球壳在匀强外电场中的场强分布是电动力学中的经典题目,也是大家所熟悉的题目,但均匀电场中出现两个导体球或球壳(二聚体)时的场强却少有讨论.两导体球电极化所引起的导体球间电磁场的局域增强是表面等离 ...
- python包的中 _init _.py文件介绍
python包的中 _init _.py文件介绍 我们新建python包时常常会看到一个__init _.py文件. 作用介绍: 一:这个文件是属于python包的,这个文件用作于标识python ...
- sql错误索引中丢失_收集,汇总和分析丢失SQL Server索引统计信息
sql错误索引中丢失 描述 (Description) Indexing is key to efficient query execution. Determining what indexes a ...
- python命名规则数字开头的成语_浅谈Python中带_的变量或函数命名
搜索热词 Python 的代码风格由 PEP 8 描述.这个文档描述了 Python 编程风格的方方面面.在遵守这个文档的条件下,不同程序员编写的 Python 代码可以保持最大程度的相似风格.这样就 ...
- 纳米二氧化硅修饰中孔ZSM-5沸石微球/含钆介孔二氧化硅海藻酸钠纳米微球
纳米二氧化硅修饰中孔ZSM-5沸石微球的制备: 其特征在于是一种具有晶内和晶间两类中孔的微球,该微球是由具有晶内中孔的纳米沸石晶粒自聚而形成的,微球的直径为4-8μm,纳米沸石晶粒粒径为15-50nm ...
- 用 java实现双色球号码生成系统;(在装满33个红色球池中连续抽取6个红球; 在一个装满16颗球的蓝色球池中抽取1个蓝球。)
用实际抓球实现(模仿现实变量) public class TestLottery1 {/*双色球号码生成算法一:模仿现实情况,在一个装满33个球的球池中连续抽取6个红球:在一个装满16颗球的球池中抽取 ...
- 管理系统中计算机应用课件,管理系统中计算机应用_第三章课件.ppt
<管理系统中计算机应用_第三章课件.ppt>由会员分享,提供在线免费全文阅读可下载,此文档格式为ppt,更多相关<管理系统中计算机应用_第三章课件.ppt>文档请在天天文库搜索 ...
最新文章
- 图片上传(加水印、缩略图、远程保存)的简单例子
- TLS与openssl学习总结(三)-实操篇
- toeplitz--生成托普利兹矩阵
- javascript 模板引擎基本原理
- react java编程_快速上手React编程 PDF 下载
- 20180802总结
- 2017.9.13 序列维护 思考记录
- 《数学之美》—贾里尼克和现代语言处理
- Xcode 9: An error occurred uploading to the iTunes Store. iTunes Store Operation Failed
- DRF使用超链接API实现真正RESTful
- docker 配置 CA验证
- 用matlab画散点图并用光滑曲线连接(样条插值)
- C语言正弦和余弦的值
- AI前沿论坛会议—文字智能和游戏智能总结篇
- 免费期刊下载——超星发现
- 2021中国市场十大IT热点
- 时间戳指什么呢?(通俗易懂的简介大白话)
- 电商后台系统产品逻辑全解析
- linux全角半角切换,教您输入法全角和半角怎么切换
- 大数据处理的关键技术有哪些?