




已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【译】光线跟踪:理论与实现(一) 简介光线跟踪的目的是为了模拟自然现象:你能见到各种颜色是因为太阳发射出来的光线,经过各种自然物体的反射或折射后,最终进入你的眼睛。若我们暂时不去计较其他因素,所有的这些光线都应该是直线。如 图所示,黄色的光直接从太阳射入照相机中;红色的光线在跟场景发生发射后到达照相机,而蓝色的光线被玻璃球折射后命中照相机。图中没有画出的是那些无法到 达观察者的光线,这些光线也是我们不从光源往照相机进行跟踪的原因,而是采用想反的路径。上图标识的是一种理想情形,因为光线的方向没有影响。 从上面我们得到一个启示:与其等待光源发射一条光线穿过一个目前颜色还是黑色的像素,不如我们自己从照相机发射光线去穿过平面的每个像素,去观察这些光线能击中几何体上的哪些像素。/-/Rayclassdefinition/-classRaypublic:Ray():m_Origin(vector3(0,0,0),m_Direction(vector3(0,0,0);Ray(vector3&a_Origin,vector3&a_Dir);voidSetOrigin(vector3&a_Origin)m_Origin=a_Origin;voidSetDirection(vector3&a_Direction)m_Direction=a_Direction;vector3&GetOrigin()returnm_Origin;vector3&GetDirection()returnm_Direction;private:vector3m_Origin;/光线的起点vector3m_Direction;/光线的方向;一条光线有它的起点和方向。当从照相机发射光线时,起点一般是一个固定点,并且光线会穿过屏幕表面的像素。/-/Firesraysinthesceneonescanlineatatime,fromleft/toright/-boolEngine:Render()/renderscenevector3o(0,0,-5);/initializetimerintmsecs=GetTickCount();/resetlastfoundprimitivepointerPrimitive*lastprim=0;/renderremaininglinesfor(inty=m_CurrLine;y(m_Height-20);y+)/逐条扫描线处理m_SX=m_WX1;/renderpixelsforcurrentlinefor(intx=0;x255)red=255;if(green255)green=255;if(blue255)blue=255;m_Destm_PPos+=(red16)+(green100)/returncontroltowindowssothescreengetsupdatedm_CurrLine=y+1;returnfalse;/alldonereturntrue;注意这段代码:vector3o(0,0,-5);vector3dir=vector3(m_SX,m_SY,0)-o;NORMALIZE(dir);Rayr(o,dir);一条光线起始点在o,方向朝向屏幕平面上的一个位置,并且方向进行了单位化处理,从而建立了这条光线。屏幕平面指的是一个漂浮在虚拟世界的一个矩形,用来表示屏幕。代码中它以原点为中心,宽为8个单位,高为6个单位,这对于800*600的分辨率是合适的。你可以对这个平面做各种处理:若你将它移开照相机,则光线的宽度就变窄,从而物体会在屏幕上变大。若你旋转这个平面(且照相机以它为中心),你会得到虚拟世界的另一种视图。接下来,我们需要一个场景来进行光线跟踪。一个场景中包含各种元素:如球体和平面等几何物体。你也可以使用三角面片,并且用这些三角面片来构造其他各种元素。元素Sphere和PlanePrim是从Primitive继承下来的,每个元素都有一个Material,并且都实现了方法Intersect和GetNormal./-/Sceneclassdefinition/-classScenepublic:Scene():m_Primitives(0),m_Primitive(0);Scene();voidInitScene();intGetNrPrimitives()returnm_Primitives;Primitive*GetPrimitive(inta_Idx)returnm_Primitivea_Idx;private:intm_Primitives;Primitive*m_Primitive;/保存的是指向各种元素的指针;voidScene:InitScene()m_Primitive=newPrimitive*100;/最多100个立体元素/groundplanem_Primitive0=newPlanePrim(vector3(0,1,0),4.4f);m_Primitive0-SetName(plane);m_Primitive0-GetMaterial()-SetReflection(0);m_Primitive0-GetMaterial()-SetDiffuse(1.0f);m_Primitive0-GetMaterial()-SetColor(Color(0.4f,0.3f,0.3f);/bigspherem_Primitive1=newSphere(vector3(1,-0.8f,3),2.5f);m_Primitive1-SetName(bigsphere);m_Primitive1-GetMaterial()-SetReflection(0.6f);m_Primitive1-GetMaterial()-SetColor(Color(0.7f,0.7f,0.7f);/smallspherem_Primitive2=newSphere(vector3(-5.5f,-0.5,7),2);m_Primitive2-SetName(smallsphere);m_Primitive2-GetMaterial()-SetReflection(1.0f);m_Primitive2-GetMaterial()-SetDiffuse(0.1f);m_Primitive2-GetMaterial()-SetColor(Color(0.7f,0.7f,1.0f);/lightsource1m_Primitive3=newSphere(vector3(0,5,5),0.1f);m_Primitive3-Light(true);m_Primitive3-GetMaterial()-SetColor(Color(0.6f,0.6f,0.6f);/lightsource2m_Primitive4=newSphere(vector3(2,5,1),0.1f);m_Primitive4-Light(true);m_Primitive4-GetMaterial()-SetColor(Color(0.7f,0.7f,0.9f);/setnumberofprimitivesm_Primitives=5;这个方法中我们加入了一个地表平面,两个球体以及2个光源。现在就开始跟踪光线了,首先来看下处理的伪代码:ForeachpixelConstructrayfromcamerathroughpixelFindfirstprimitivehitbyrayDeterminecoloratintersectionpointDrawcolor为了确定光线命中的最近的一个元素,我们必须对其所有可能的交点做测试。/-/Naiveraytracing:Intersectstheraywitheveryprimitive/inthescenetodeterminetheclosestintersection/-Primitive*Engine:Raytrace(Ray&a_Ray,Color&a_Acc,inta_Depth,floata_RIndex,float&a_Dist)if(a_DepthTRACEDEPTH)return0;/traceprimaryraya_Dist=1000000.0f;vector3pi;Primitive*prim=0;intresult;/findthenearestintersectionfor(ints=0;sGetNrPrimitives();s+)Primitive*pr=m_Scene-GetPrimitive(s);intres;if(res=pr-Intersect(a_Ray,a_Dist)prim=pr;result=res;/0=miss,1=hit,-1=hitfrominsideprimitive/nohit,terminaterayif(!prim)return0;/handleintersectionif(prim-IsLight()/wehitalight,stoptracinga_Acc=Color(1,1,1);else/determinecoloratpointofintersectionpi=a_Ray.GetOrigin()+a_Ray.GetDirection()*a_Dist;/tracelightsfor(intl=0;lGetNrPrimitives();l+)Primitive*p=m_Scene-GetPrimitive(l);if(p-IsLight()Primitive*light=p;/calculatediffuseshadingvector3L=(Sphere*)light)-GetCentre()-pi;NORMALIZE(L);vector3N=prim-GetNormal(pi);if(prim-GetMaterial()-GetDiffuse()0)floatdot=DOT(N,L);if(dot0)floatdiff=dot*prim-GetMaterial()-GetDiffuse();/adddiffusecomponenttoraycolora_Acc+=diff*prim-GetMaterial()-GetColor()*light-GetMaterial()-GetColor();/returnpointertoprimitivehitbyprimaryrayreturnprim;其中这段代码:/findthenearestintersectionfor(ints=0;sGetNrPrimitives();s+)/对所有的元素做测试Primitive*pr=m_Scene-GetPrimitive(s);intres;if(res=pr-Intersect(a_Ray,a_Dist)/找到第一个命中的元素prim=pr;result=res;/0=miss,1=hit,-1=hitfrominsideprimitive对场景中的所以元素做循环处理,为每个元素调用其Intersect方法,这个方法以一条光线为参数,返回一个整数表明是命中还是没有命中,以及相交的距离是在体内还是体外。除此以外还会记录下最近相交的记录。一旦我们知道光线命中的是那个元素,那么就可以来计算光线的颜色了。若只是简单地使用元素的材质颜色就太简单了,并且结果颜色也很枯燥。因此,我们使用两个点光源来计算散射阴影。/determinecoloratpointofintersectionpi=a_Ray.GetOrigin()+a_Ray.GetDirection()*a_Dist;/tracelightsfor(intl=0;lGetNrPrimitives();l+)Primitive*p=m_Scene-GetPrimitive(l);if(p-IsLight()Primitive*light=p;/calculatediffuseshadingvector3L=(Sphere*)light)-GetCentre()-pi;NORMALIZE(L);vector3N=prim-GetNormal(pi);if(prim-GetMaterial()-GetDiffuse()0)floatdot=DOT(N,L);/点积if(dot0)floatdiff=dot*prim-GetMaterial()-GetDiffuse();/adddiffusecomponenttoraycolora_Acc+=diff*prim-GetMaterial()-GetColor()*light-GetMaterial()-GetColor();这段代码计算从相交点(pi)到光源(L)的向量,并用这个向量和相交点的单位向量的叉积来计算出光源的亮度。这个计算出的亮度是元素朝向光源的那一点被光源照亮,而其他点就是阴暗的了。叉积大于0为了防止面与光源反向。好了,这一篇就到这里了,没有反射,没有折射,更没有加入阴影,这些东东在后续的文章中会慢慢加入的,而这只是最简单的一个光线跟踪而已Phinecos(洞庭散人) 专注于开源技术的研究与应用Phinecos(洞庭散人) 专注于开源技术的研究与应用【译】光线跟踪:理论与实现(二)Phong模型,镜面反射及阴影 译注个人先对第一篇的 流程做个总结,从一个固定的光源点向一定范围发射出一些主要的光线,想象光线前方有一个巨大的虚拟平面,那么我们要做的就是决定这个虚拟平面上每个像素点 的颜色是什么。如何决定呢?很简单,我们跟踪光线前进,看光线会最先与前面场景中哪个几何体发生相交,那么就根据相交点来决定虚拟平面上对应的点的颜色值 (比如上一篇中就利用了相交点处几何体的材质颜色与灯光颜色,还加上了散射因子来决定对应的像素点的颜色)。Introduction在第一篇中介绍了光线跟踪的基础知识:从一个照相机发射出光线,让这些光线穿过一个屏幕平面进入到场景中,跟踪光线从而寻找出其与几何体最近的相交点,并简单地使用一个点积值来计算散射度,最终完成对像素点颜色值的计算。下图所示的是第一篇中那个简单的光线跟踪发射到场景中的光线,它们可以击中光源,或者一个几何体,也可以啥也没打中。这里没有反射,也没有折射。我们称之为” primary rays”.当然与之对应的光线称之为”secondary rays”,如下图所示:图中的蓝线是反射光线,绿线是折射光线。后者比前者要难计算,但也是可以做的。它的计算主要涉及到折射因子和折射定律。红线是用来探测光源的。一般来说,如果你想计算散射光,那么若对于相交点来说光源是可见的,就对点积乘以1,否则就乘以0,将其排除出去。当然若光源是半可见就乘以0.5.如果你跟踪从照相机中发出的一条黄线的话,你会发现每条黄线都可以产生出一系列secondary rays:一条反射光线,一条折射光线,并为每个光源产生一条阴影线。这些光线产生后(除了阴影线外)都可以被视为普通的光线。这意味着一条反射光线可以再被反射和折射,这种方法叫做“递归光线跟踪”。每条新产生的光线都增加了它先前光线聚集的地方的颜色,最终每条光线都对最开始由primary ray穿过的像素点的颜色做出了自己的贡献。为了防止无穷的循环,一般会对递归的层次有一个限制。Reflections为了对于一个已知的平面法向量时对一条光线进行反射,我们使用下面这个公式:这里R是被反射的向量,V是入射光向量,N是平面法向量这段计算的代码就放到为每个光源计算散射光的循环后面:/calculatereflectionfloatrefl=prim-GetMaterial()-GetReflection();if(refl0.0f)/几何体材质的反射度大于vector3N=prim-GetNormal(pi);/几何体的法向量vector3R=a_Ray.GetDirection()-2.0f*DOT(a_Ray.GetDirection(),N)*N;if(a_DepthGetMaterial()-GetColor();/颜色值中加入反射光的贡献值加入了反射后看起来效果要比上一篇里好些了。注意两个球彼此之间是会互相反射的,而且球也会反射地表平面。Phong光照模型到目前为止我们使用的散射光着色对于非刚体来说是不错的,但对于比较有光泽的物体来说就不够好了。此外,我们无法插手去控制它,更别说想去控制光照的强度了。先来看看下面这幅图:左图表示的是我们目前使用的光照模型:法向量与光源向量的点积,可以看出在黑白色之间有一个线性的过渡。右图使用和左图一样的点积,但权值提高到50。这样一来,当两个向量很接近时就会出现一个很亮的斑点,然后迅速降低到0.结合进这些改进的话,我们就获得了一些灵活性。一个物体可以有散射,有镜面反射,而我们可以通过调整其权值来设置高亮区的大小。但这仍是不够的。散射光是可以的:一个散射物体会向各个方向散射光线,所以它最亮的地方恰好就是物体面向光源那儿。用法向量和到光源的向量之间的点积就是这个结果。镜 面光就有点不同了,一般来说,镜面高亮区是对光源的散射性反射。你可以观察下生活中这样的情况:拿一个闪闪发亮的物体,把它放到桌子上并置于灯下,然后移 动的视线。你会注意到当你移动眼睛时物体上的发光点并不是始终保持在同一个位置处。这是因为反射作用,当你的视点变化时,它的位置就自然发生改变。Phong于是提出了如下的光照模型,它最大的特点就是将反射向量考虑进来了。intensity=diffuse*(L.N)+specular*(V.R)n(这里L是从相交点到光源的向量,N是平面法向量,V是视线方向,R是L在表面上的反射向量)。注意这个公式包含了散射和镜面反射光。vector3V=a_Ray.GetDirection();/光线方向vector3R=L-2.0f*DOT(L,N)*N;floatdot=DOT(V,R);if(dot0)floatspec=powf(dot,20)*prim-GetMaterial()-GetSpecular()*shade;/addspecularcompon
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年生物质能与煤炭耦合燃烧技术在玻璃行业节能减排效果评估报告
- 2025中国文教专家标准聘用合同范本
- 2025-2032年中国新能源汽车市场国际化战略研究报告
- 2025物业管理员聘用合同范文
- 夫妻离婚财产分割与债务处理协议
- 《复杂离婚案财产分割及房产、土地权益协议》
- 数字化赋能下的2025年公路货运效率提升与成本控制分析报告
- 2025年解除租赁合同协议书
- 现代公路货物运输合同:运输工具维护知识与保养
- 贷款担保合同签订时间节点与法律适用分析
- 音乐核心素养培训课件
- 重庆机电职业技术大学《高等数学Ⅱ》2025-2026学年期末试卷(A卷)
- 中小学生心理健康测评表
- 沔城高中生研学活动方案
- 手术室工人的工作职责
- 拥军活动策划方案
- 2025年广东省中考语文试卷真题(含答案解析)
- 社区治理志愿服务课件
- 养老服务机构客户服务管理制度及流程体系
- 脑梗死的中医护理查房
- 河南省人民防空工程维护管理技术规程2025
评论
0/150
提交评论