设为首页 收藏本站
查看: 1401|回复: 0

[经验分享] DDA(Digital Differential Analyzer, 数值微分法) -

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-1-22 11:12:39 | 显示全部楼层 |阅读模式
计算机图形学中,经常会遇到一些计算机中”经典“的问题。例如,如何利用计算机”离散“的特质,模拟现实中”连续“的概念?关于这个问题的一个具体应用,就是如何利用计算机”画直线“的问题。我们知道在纯粹抽象的数学中,一条直线用y=mx+b就可以表达(其中m是斜率);但如果要画在计算机屏幕上,就没那么容易:因为计算机屏幕是由许多分散的像素格子组成的,你需要决定在什么时候换行或者换列。这种模拟的本质,还是”插值“问题。直线是最简单的情况,往复杂点说,就会有考虑如何插值三角形甚至多边形的情况。不过它们都是”直线“插值的复杂应用,下面就不多说了。

DDA是一种处理此种问题的经典算法。算法思想倒也不难:

【准备阶段】

1) 给定一条线段的起点(x1, y1)和终点(x2, y2),分别计算在两轴上的差值 △y = y2 - y1 和 △x = x1 - x2。

2) 比较△y和△x二者谁比较大,大的那一个就作为遍历的总步数。steps = max(△x, △y)。

3) 分别计算在x和y方向上单步的步距。 dx = △x/steps,dy = △y/steps。注意此时dx和dy必然一个等于1,一个介于0-1之间(浮点数)


【遍历阶段】

4)△x和△y谁大,谁就作为插值的主序方向。意味着每次插值都是朝这个方向行进一步。比如△x大,那么假设当前在格子(xi, yi)处,决定下一个格子时,由于在x方向是主序方向,所以朝x方向行进一步得到xi+1。剩下的就是决定y方向上到底是yi呢还是yi+1呢。



5)到底是yi还是yi+1,要看根据y = m(xi+1) + b计算出真实的y等于多少。这时的y计算出来的是浮点数,根据float2Int的一些规则,转换成对应的整形然后找到对应的格子。float2Int的转换规则要看具体情况,四舍五入还是直接截取,看效果吧。



6)重复4)-5)步



DDA算法直接了当,简单易懂。不过它的计算过程中涉及到许多浮点数运算,这在当今的CPU设计架构中运算成本较大,也可视为其运算复杂度较高。下面的Bresenham line's algorithm就是对其的一种改进。





- Bresenham line's algorithm -

Bresenham line's algorithm 是DDA的一种改进算法。它与DDA相比有质量和效率的两点改进:

1)质量方面的改进。 比如还是以△x为主序方向行进时,决定下一个点是落在yi还是yi+1,不仅仅考虑真实计算出来的y等于多少,还要考虑这个y值是离yi更近还是离yi+1更近。谁近就画在谁的格子里。这一点显然比DDA中思考问题的方式更加make sense。


2)效率方面的改进。根据上一点的判断准则,再加上一系列的递归推导,最后简化到只存在整形的加减运算以及比较操作。这在当今CPU的架构中运算成本相对来说非常便宜,因此效率更高。具体的推导细节,参见这篇 DERIVATION OF THE BRESENHAM’S LINE ALGORITHM





- Voxel Traversal used in the Grid-Accelerator in PBRT -

我正在看pbrt的第4章。这章主要讲了有关场景管理组织的一些技术,目的是为了提高射线相交测试(ray intersection tests)的效率。主要的手段有三种,Grid-Based, BVH 和 KD-Tree。目前正看到第一种,Grid-Based,基于网格的场景管理技术 。

基于网格的场景管理方法,相当于把整个场景看作是一个大的bouding box,然后对这个box所在的空间分别在三个维度上划分成一格一格的。然后将场景中的primitives与各个发生overlap的格子”关联“起来。接着,从射线的方位出发,遍历(traverse)这个网格系统,对于与射线发生相交的格子,再在里面遍历与之关联的所有primitives,对遍历到的每个primitive都做一次相交测试。当然这当中的细节还有很多,就不赘述了。总之这种算法的思想可以描述为”分而治之“。通过每个格子的空间管理与之有关的primitives,测试某个格子的时候就不必考虑其他格子里的primitives,从而可以有效降解其遍历场景的复杂度。

这里,我想强调下射线是如何遍历这个网格系统的。其方法也是DDA算法的一种改进,书中说非常像Bresenham line's algorithm。但我仔细观察了一下,和Bresenham的算法还是不一样的。这里的关键是利用的是射线的参数(parametric)方程,那个参数t(作为沿着射线方向偏离起点的距离)是很重要的。当决定下一点究竟是朝x方向,y方向还是z方向步进时,要看这条射线”最先打到哪个方向的下一格子的边界“。哪个方向的边界先被打到,就朝哪个方向步进一次。这样一来,这种算法就不是依靠决定”哪个方向是主序“的思路进行的了,每次判断步进时三个方向皆有可能步进。这点与经典的DDA(包括Bresenham)算法都非常不同。

我知道我没说清楚,刚才在网上粗略找了找,发现这篇应该才是pbrt中使用的算法:A Fast Voxel Traversal Algorithm for Ray Tracing。(我没细看,大体觉得差不了)。欢迎指正校对勘误拍砖头,谢谢。




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-14484-1-1.html 上篇帖子: windows下配置ssh访问github 下篇帖子: centos 搭建简单git服务器
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表