[翻译]XNA 3.0 Game Programming Recipes之thirty-two

本文详细介绍了如何通过使用指针射线和二进制搜索算法来精确计算3D地形上的碰撞点,适用于游戏开发、3D建模等领域。通过结合线性搜索与二进制搜索,确保在复杂地形中准确捕捉到最近的碰撞点。
PS:自己翻译的,转载请著明出处格
                                                5-10 计算在指针和地形:Surface Picking之间的碰撞点
问题
                你想找到准确的3D坐标在你的地形上在这个位置被你的指针所指出。这是必须的,如果你想要在地形上指出大的位置,为你的对象移动到或当布置一个对象在一个地形上时。
解决方案
                做为一个讨论在4-19节,2D点在你的屏幕上,用你的指针所指示,相应的条射线在你的3D屏幕中。在这一节,你将会利用这个射线直到你撞击到地形。
                你可以做这个用一个二进制收索算法,它能够给你一个碰撞的位置用一个精确度的选择。
                鉴于hilliness的地形,它可能有多个碰撞点在射线和地形之间,如图5-20所示。因此,你想在二进制搜索用线性搜索之前,所以你确保检测最接近相机的碰撞。
它是如何工作的
                这个方法转化为2D屏幕指针的位置到3D射线。它充分解释了在4-19节的第一部分。
 1 private Ray GetPointerRay(Vector2 pointerPosition)        
 2 {
 3      Vector3 nearScreenPoint=new Vector3(pointerPosition.X,pointerPosition.Y,0);
 4      Vector3 farScreenPoint=new Vector3(pointerPosition.X,pointerPosition.Y,1);
 5      Vector3 near3DWorldPoint=device.Viewport.Unproject(nearscreenPoint,moveCam.ProjectionMatrix,moveCam.ViewMatrix,Matrix.Identity);
 6      Vector3 far3DWorldPoint=device.Viewport.Unproject(farScreenPoint,moveCam.ProjectionMatrix,moveCam.ViewMatrix,Matrix.Identity);
 7      Vector3 pointerRayDirection=far3DWorldPoint-near3DWorldPoint;
 8      Ray pointerRay=new Ray(near3DWorldPoint,pointerRayDirection);
 9      return pointerRay;
10 }
注意:在这个版本,你不能规格化射线的方向。一会我将会解释。
                现在你知道了指针射线,你已经准备好检测在射线和地形之间的碰撞。
Binary Search
                这个射线包含起始点(在这种情况下,射线穿透了近裁剪平面)和方向。图5-19显示射线和地形。起始点作为A点。射线的方向是一个向量在A点到B点之间。
                总的想法在二进制收索之后是十分直观的。你开始于两个点,A和B,它们可以保证碰撞点在它们之间。在点A和B之间计算这个点去找到他们的中点,它被点1在图5-19所指示。你可以检查这个点是否在地形的上方或下方。如果这个点是在地形的上方(如在这种情况下的图象),你知道碰撞点是在点1和点B之间的。
                接下来。找到点2,在点1和B之间。这个点是在地形的下面,所以你知道碰撞点在点1和点2之间。
                你继续缩小。观察点3,在点1和点2之间。这个点又一次在地形的上面,所以这个碰撞在3和2之间。
                接下来,点4在3和2之间在地形的下面,所以碰撞在3和4之间。
                最后,检查点5,它是在3和4之间的。你发现点5的高度是非常接近地形的高度在(X,Z)位置,所以你已经发现了碰撞点。
Finding Point A and Point B                     
                在准备使用二进制收索,你需要开始于两个点,A和B,在你的射线上,你要确保碰撞点在它们之间。
                您可以放心使用的指针射线起始位置作为A点,因为它是射线上最接近摄象机的点(它是布置在近景剪裁平面;详细参见4-19节)。
                现在,你将会得到这个点它是射线穿透远景平面作为点B。这是一个不坏的选择,因为它是最远的距离点在射线上。仍然可以被摄象机看见。
                作为你能看见的在GetPointerRay方法如4-19所解释的那样,这个pointerRay.Direction相当于你需要同点A到B增长的向量。
The Binary Search Method
                现在你知道了点A到点B的方向了,你已经准备去检测与地形的碰撞了。这个二进制收索算法在前面已经解释过了,转化成伪代码,成为这:
                只要在高度差异之间当前的点和地形下面太大,做下面几点:
                a.分射线的方向一半。
                b.增加结果的方向到当前的点去获得下一个点。
                c.如果下一个点是同样在地形的上面,保存下一个点作为当前的点。
                想象一下,这是走的射线的每一步,在你脚步前面的地方,你检查你的脚步是否在地形之下。这种情况并非如此,你继续同时每一步都步长减半。一旦你放置你的脚步在你的地形下面,你收回你的脚步,并试图减少一半,知道你结束你的脚步正确的在地形的位置上,与地形相碰撞。
                代码如下:
 1 private Vector3 BinarySearch(Ray ray)
 2 {
 3     float accuracy=0.01;
 4     float heightAtStartingPoint=terrain.GetExactHeightAt(ray.Position.X,-ray.Position.Z);
 5     float currentError=ray.Position.Y-heightAtStartingPoint;
 6     while(currentError>accuracy)
 7     {
 8         ray.Direction/=2.0f;
 9         Vector3 nextPoint=ray.Position+ray.Direction;
10         float heightAtNextPoint=terrain.GetExactHeightAt(nextPoint.X,-nextPoint.Z);
11         if(nextPoint.Y>heightAtNextPoint)
12         {
13              ray.Position=nextPoint;
14              currentError=ray.Position.Y-heightAtNextPoint;
15         }
16     }
17     return ray.Position;
18 }
                 你开始计算不同的高度差在其始点在你射线上的和地形之下的点之间。
                 该while将循环播放,直到这种差异小于您预定准确性0.01f 。如果差异仍然较大,您减半步长和计算在射线上的下一点 。如果这个下一个点是在地形之上,你走到这一点,并计算出在这一点高度差。如果没有,什么也不做,以便下一次步长再次减半。
                 在while循环之后,ray.Position将包含一个在射线上的位置,它与地形的高度差小于0.01f
                 这是你怎么样使用这个方法,开始射线AB用创建GetPointerRay:
1 pointerPos=BinarySearch(pointerRay);
注意:如果你的指针没有超过地形,这个方法将永远留在while循环中。因此,它能被用来打破while循环,如果一个对应的价值是比开端大,在这节后面的代码会显示:
Problems with the Binary Search
                在大数情况,二进制搜索会做得很出色,但在某些情况下,它只会一败涂地,草草收场,如图5-20所示
                由于而进制检查不会检查点0和1之间的地形高度,在第一个山岗和射线之间的碰撞是检测不到的,同样的结果(点5)作为射线和地形之间的碰撞返回。
                为了解决这个,二进制搜索应加上线性搜索,这是简单比较二进制搜索。
Linear Search
                在线形收索里,你准备去分你的射线成很多相等的距离,例如,八部分,如图5-21所示。
                你简单的利用你的射线用相同的大小,到你一个点在地形下面为止。这将会不会给你一个准确的结果,但是至少你会检测到射线与第一个山岗相撞了。
                由于在图5-21中点1和点2都不接近地形,你想使用二进制收索在射线上的点1和点2之间去精确的找到碰撞点。
                这LinearSearch方法接收整个射线在A和B之间,分成相等的几份,返回相应碰撞占据的某部分:
 1 private Ray LinearSearch(Ray ray)
 2 {
 3     ray.Direction/=300.0f;
 4     Vector3 nextPoint=ray.Position+ray.Direction;
 5     float heightAtNextPoint=terrain.GetExactHeightAt(nextPoint.X,-nextPoint.Z);
 6     while(heightAtNextPoint<nextPoint.Y)
 7     {
 8          ray.Position=nextPoint;
 9          nextPoint=ray.Position+ray.Direction;
10          heightAtNextPoint=terrain.GetExactHeightAt(nextPoint.X,-nextPoint.Z);
11     }
12     return ray;
13 }
                在这个例子中,射线被划分至少30份。逐渐增多的这个值将会增加检测概率变的最高,但是要求更多的处理能力。
                对于每一个点,你计算下一个点,检查下一个点是否在地形的上面或下面。只要它是在地形的上面,继续。如果下一个点在地形的下面,返回当前的射线包括在碰撞之后的这个点,和发生碰撞的那一份。
                这个射线立即被用来开始BinarySearch的方法:
1 Ray shorterRay=LinearSearch(pointerRay);
2 pointerPos=BinarySearch(shorterRay);
Application-Specific Optimization
                线形收索将确保你检测到小的高峰,同时下面的二进制收索将给你当前你想要的。
                在前面的代码,你已经取得了点A和B作为射线碰撞点,在近景和远景的剪辑平面。这很好,但是如果在近景和远景剪辑平面之间的距离很大,这个射线将同样很大。意思是你将会做大量的没有用的检测在地形上或下的距离。
                相反,你考虑的只是射线能够碰撞地形产生的高度。本书的所用的地形,最大值是30,同时最小值是0,所以它最好能找到在你射线上的点,Y坐标是30,用这个作为起始点A。接下来,用Y=0找到点在你的射线,用这个点做为结束点B。
                由此产生的射线用这个方法构成:
 1 private Ray ClipRay(Ray ray,float highest,float lowest)
 2 {
 3     Vector3 oldStartPoint=ray.Position;
 4     float factorH=-(oldStartPoint.Y-heighest)/ray.Direction.Y;
 5     Vector3 pointA=oldStartPoint+factorH*ray.Direction;
 6     float factorL=-(oldStartPoint.Y-lowest)/ray.Direction.Y;
 7     Vector3 pointB=oldStartPoint+factorL*ray.Direction;
 8     Vector3 newDirection=pointB-pointA;
 9     return new Ray(pointA,newDirection);
10 }
                为了找到这点在射线上用一个特殊Y坐标,找到Y值和初始射线的开始点的Y坐标之间的差值。如果你知道射线的方向的高度差异,你知道射线的哪一部分(保存在factor)你应该增加到开始的点去达到要求Y值的点。
注意:oldStartPoint的Y坐标是正的,同时Y坐标的方向将会为负作为射线的下降。你要factor成为正值,用-标识。
                如果你起始于这个结果的射线,你将会需要去很多检测在你的LinearSearch去结束用同样的峰值检波率。
代码
      参看上述代码!

转载于:https://www.cnblogs.com/315358525/archive/2009/08/07/1541349.html

标题SpringBoot智能在线预约挂号系统研究AI更换标题第1章引言介绍智能在线预约挂号系统的研究背景、意义、国内外研究现状及论文创新点。1.1研究背景与意义阐述智能在线预约挂号系统对提升医疗服务效率的重要性。1.2国内外研究现状分析国内外智能在线预约挂号系统的研究与应用情况。1.3研究方法及创新点概述本文采用的技术路线、研究方法及主要创新点。第2章相关理论总结智能在线预约挂号系统相关理论,包括系统架构、开发技术等。2.1系统架构设计理论介绍系统架构设计的基本原则和常用方法。2.2SpringBoot开发框架理论阐述SpringBoot框架的特点、优势及其在系统开发中的应用。2.3数据库设计与管理理论介绍数据库设计原则、数据模型及数据库管理系统。2.4网络安全与数据保护理论讨论网络安全威胁、数据保护技术及其在系统中的应用。第3章SpringBoot智能在线预约挂号系统设计详细介绍系统的设计方案,包括功能模块划分、数据库设计等。3.1系统功能模块设计划分系统功能模块,如用户管理、挂号管理、医生排班等。3.2数据库设计与实现设计数据库表结构,确定字段类型、主键及外键关系。3.3用户界面设计设计用户友好的界面,提升用户体验。3.4系统安全设计阐述系统安全策略,包括用户认证、数据加密等。第4章系统实现与测试介绍系统的实现过程,包括编码、测试及优化等。4.1系统编码实现采用SpringBoot框架进行系统编码实现。4.2系统测试方法介绍系统测试的方法、步骤及测试用例设计。4.3系统性能测试与分析对系统进行性能测试,分析测试结果并提出优化建议。4.4系统优化与改进根据测试结果对系统进行优化和改进,提升系统性能。第5章研究结果呈现系统实现后的效果,包括功能实现、性能提升等。5.1系统功能实现效果展示系统各功能模块的实现效果,如挂号成功界面等。5.2系统性能提升效果对比优化前后的系统性能
在金融行业中,对信用风险的判断是核心环节之一,其结果对机构的信贷政策和风险控制策略有直接影响。本文将围绕如何借助机器学习方法,尤其是Sklearn工具包,建立用于判断信用状况的预测系统。文中将涵盖逻辑回归、支持向量机等常见方法,并通过实际操作流程进行说明。 一、机器学习基本概念 机器学习属于人工智能的子领域,其基本理念是通过数据自动学习规律,而非依赖人工设定规则。在信贷分析中,该技术可用于挖掘历史数据中的潜在规律,进而对未来的信用表现进行预测。 二、Sklearn工具包概述 Sklearn(Scikit-learn)是Python语言中广泛使用的机器学习模块,提供多种数据处理和建模功能。它简化了数据清洗、特征提取、模型构建、验证与优化等流程,是数据科学项目中的常用工具。 三、逻辑回归模型 逻辑回归是一种常用于分类任务的线性模型,特别适用于二类问题。在信用评估中,该模型可用于判断借款人是否可能违约。其通过逻辑函数将输出映射为0到1之间的概率值,从而表示违约的可能性。 四、支持向量机模型 支持向量机是一种用于监督学习的算法,适用于数据维度高、样本量小的情况。在信用分析中,该方法能够通过寻找最佳分割面,区分违约与非违约客户。通过选用不同核函数,可应对复杂的非线性关系,提升预测精度。 五、数据预处理步骤 在建模前,需对原始数据进行清理与转换,包括处理缺失值、识别异常点、标准化数值、筛选有效特征等。对于信用评分,常见的输入变量包括收入水平、负债比例、信用历史记录、职业稳定性等。预处理有助于减少噪声干扰,增强模型的适应性。 六、模型构建与验证 借助Sklearn,可以将数据集划分为训练集和测试集,并通过交叉验证调整参数以提升模型性能。常用评估指标包括准确率、召回率、F1值以及AUC-ROC曲线。在处理不平衡数据时,更应关注模型的召回率与特异性。 七、集成学习方法 为提升模型预测能力,可采用集成策略,如结合多个模型的预测结果。这有助于降低单一模型的偏差与方差,增强整体预测的稳定性与准确性。 综上,基于机器学习的信用评估系统可通过Sklearn中的多种算法,结合合理的数据处理与模型优化,实现对借款人信用状况的精准判断。在实际应用中,需持续调整模型以适应市场变化,保障预测结果的长期有效性。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值