试验报告光线跟踪的实现.docx
- 文档编号:24268234
- 上传时间:2023-05-25
- 格式:DOCX
- 页数:13
- 大小:579.41KB
试验报告光线跟踪的实现.docx
《试验报告光线跟踪的实现.docx》由会员分享,可在线阅读,更多相关《试验报告光线跟踪的实现.docx(13页珍藏版)》请在冰豆网上搜索。
试验报告光线跟踪的实现
实验报告:
光线跟踪的实现
学号:
2111112041姓名:
李伟明
实验思想
从眼睛出发计算通过每个像素的光线方程,光线方程与场景中最近物体相交,计算各光源在该交点处的漫反射分量,镜面反射分量,并且叠加这些分量,递归计算光线在交点处的反射和折射光线,并且也将计算得到的各分量叠加到像素中,将该像素最后得到的总光强存储到一个二维数组里。
计算完所有像素后,使用opengl将这些像素点绘制出来。
一.创建场景
场景中创建了三个平面,七个球(其中两个大球,五个小球),两个光源。
定义一个800*800的二维数组:
rgbColorPixelColor[PixelH][PixelW],用于存储像素值。
PixelH和PixelW的预定义值为800。
二.计算光线方程
屏幕的大小为8*8,分辨率为800*800,屏幕在xoy平面上,屏幕中心位置是坐标原点。
眼睛的位置O(0,0,4),屏幕上一点D(image_x,image_y,0),光线的方向为V=D–O。
由此可以确定一条光线Ray(O,dir)。
然后求出该光线与场景中最近物体的交点。
三.光线与物体相交
1.光线与球体相交
球体方程:
(x-x1)^2+(y-y1)^2+(z-z1)^2=R^2
光线方程:
O+Vt=0;
V为单位向量,球心c(x1,y1,z1)。
由两方程可得
t^2+2V*(O-c)*t+[(O-c)*(O-c)-R^2]=0
根据方程计算出t的实数解。
具体实现如下:
//tmin就是float,inp变量在折射时用到
boolSphere:
:
intersect(Ray&r,tmin&T,bool&inp)
{
floatA=1.0;
vec3fE_C=r.getOrigin()-_center;
floatB=2*dot(r.getDirection(),E_C);
floatC=power(E_C)-pow(_radius,2);
floatD=pow(B,2)-4*A*C;
inp=false;
boolreslut=false;
if(D<0)
{
return0;
}
else
{
D=sqrtf(D);
floatt1=(-B+D)/2*A;
floatt2=(-B-D)/2*A;
if(t1>0)
{
if(t2<0.001)//问题一所在
{
if(t1 { T=t1; reslut=true; inp=true; } } else { if(t2 { T=t2; reslut=true; } } } } returnreslut; } 2.光线平面相交 首先平面的法向量N与光线方向向量V点乘,如果结果不为0,则光线与平面有交点,计算出对应交点的t值 具体实现如下 boolPlane: : intersect(Ray&r,tmin&T,bool&inp) { vec3ftmp=r.getOrigin()-_center; floatcosV_N=-dot(r.getDirection(),_normal); boolreslut=false; inp=false; if(cosV_N! =0) { floatt=dot(tmp,_normal)/cosV_N; if(t>0) { if(t { T=t; reslut=true; } } } returnreslut; } 四.慢反射光的计算 漫反射的计算公式为 ,为了实现方便,我将Kd设置成了浮点型,表示对RGB三个分量的反射强度相同,同时为了反映出物体本身的颜色属性,在计算时乘上了物体本身的颜色。 1.具体实现代码为 if(prim->_pMat.GetDiffuse()>0)//首先判断物体的漫反射系数是否大于0 { floatcosN_L=dot(N,L);//光线与交点法线的夹角的余弦值 if(cosN_L>0) {//shade是阴影开关,如果交点在阴影中则shade=0,否则shade=1 color=color+shade*cosN_L*prim->_pMat.GetDiffuse()*prim->_pMat.GetColor()*lig->_pMat.GetColor();//物体的颜色与光源的颜色混合 } } 以上代码中N为交点处的单位法向量,L为交点到光源的单位向量,dot(N,L)表示点成两个向量,prim->_pMat.GetDiffuse()为物体的慢反射系数,prim->_pMat.GetColor()为物体的颜色值,含RGB三个分量,lig->_pMat.GetColor()是光源的颜色值,含RGB三个分量。 2.效果如下 五.阴影的计算 对于场景中的每个光源创建一条阴影测试光线,判断对场景中的所有球体是否有相交,因为我的程序中平面作为了边界,所以不用考虑再内。 如果相交,则说明物体在阴影中,光线照射不到该点,设置shade=0;否则说明物体不在阴影中,光线能够照射到该点,设置shade=1。 1.具体实现代码如下 floatshade=1.0;//shade是阴影开关,如果交点在阴影中则shade=0,否则shade=1 Rayrtest(pi+SMALLF*L,L); floatmtest=10000.0; boolintest=true; for(intk=1;k<7;k++)//只测试场景中的7个球体,不测试边界的平面 { objec3D*p1=_scene->_objlist[k]; if(p1->intersect(rtest,mtest,intest)) { shade=0.0; break; } } 2.效果如下 六.Phong高光的计算 根据Phong光照模型得到的公式为 其中r=(2*dot(N,L))*N–L,我的程序中把Ks设置成浮点型,表示对RGB三个分量的镜面反射相同。 1.具体代码为 vec3fR=(2*dot(N,L))*N-L; floatcosR_V=dot(R,V); if(cosR_V>0) { floatphong=powf(cosR_V,30); color=color+shade*phong*prim->_pMat.GetSpecular()*lig->_pMat.GetColor(); } 以上代码中R为光源光线的反射向量,V为视线的方向,N为交点法向量,L为光源光线向量。 Phong的指数设置为30,prim->_pMat.GetSpecular()为镜面反射系数。 2.效果如下 七.反射光的计算 反射光线的计算公式为: Reflection_V=V-(2.0*dot(N,V))*N 其中Reflection_V为反射光的方向,V为入射光线,即视线,N为交点处的法向量。 计算反射光线并递归跟踪,其中depth是递归深度值。 还设置了一个inp变量,用于判断光线是否在物体内与物体相交,如果inp=true,则说明光线是在物体与之相交,那么就不计算它的反射分量。 1.具体代码如下 if((prim->_pMat.GetReflection()>0)&&(depth<4)) { if(! inp) { vec3fReflection_V=V-(2.0*dot(N,V))*N; pi=pi+SMALLF*Reflection_V;//问题二所在 Rayr2(pi,Reflection_V); vec3fcolorR(0.0,0.0,0.0); trace(r2,colorR,depth+1); color=color+prim->_pMat.GetReflection()*colorR*prim->_pMat.GetColor(); } } 以上代码中prim->_pMat.GetReflection()是物体的反射系数。 2.效果如下 八.折射光的计算 根据折射定理可以得到公式 其中T为折射光线的方向向量,I为入射光线,n为交点处的法向量, , 。 我的程序中,物体的折射率事先给定。 计算反射光线并递归跟踪,其中depth是递归深度值。 1.具体实现代码如下 if((prim->_pMat.GetTransmit()>0)&&(depth<4)) { floatk_n=prim->_pMat.GetN(); floatk_tran=prim->_pMat.GetTransmit(); floatn; floatcosN_V=-dot(N,V); if(inp) { n=k_n; } else { n=1.0/k_n; } floattmp=n*cosN_V-sqrtf(1+pow(n,2)*(pow(cosN_V,2)-1)); vec3fT=n*V+tmp*N; T.normal(); pi=pi+SMALLF*T;//问题二所在 Rayr1(pi,T); vec3fcolorT(0.0,0.0,0.0); trace(r1,colorT,depth+1); color=color+k_tran*colorT; } 以上代码中prim->_pMat.GetN()是得到折射率,prim->_pMat.GetTransmit()是得到物体的透明系数,N是交点的法向量,V是入射光向量。 2.效果如下 左边大球后面有一个红色小球,右边打球后面有四个蓝色小球。 左边的球透明系数为0,所以没有折射效果,右边的球透明系数不为0,所以能折射出后面四个小球。 九.绘制 在main函数中使用glut创建初始化窗口,利用OpenGL绘制点的函数将存储在数组PixelColor[PixelH][PixelW]中的值绘制出来。 具体绘制代码如下: voiddraw() { floatdx=2.0/PixelW; floatdy=2.0/PixelH; GLfloatx=-1.0; GLfloaty=-1.0; glBegin(GL_POINTS); for(inti=0;i { x=-1.0f; for(intj=0;j { glColor3f(rayT.PixelColor[i][j].x,rayT.PixelColor[i][j].y,rayT.PixelColor[i][j].z); glVertex2f(x,y); x+=dx; } y+=dy; } glEnd(); } 一十.遇到的问题 1.问题一 计算光线在球体内与球相交时,理论上得到的两个交点的其中一个交点是光线的原点,所以得到的t值中其中一个应该是为0,我的程序中是交点为t2的值。 但是在程序实现中,由于计算精度误差的原因,计算得到的t2会是一个略大于0的值,因此如果在判断是为“t2<=0”,则程序运行后球体上会出现一些噪点。 如下图所示: 所以在判断是若设定t2小于一个小的浮点数,则这个问题就能解决。 我的程序中设置了“t2<0.0001”。 3.问题二 在计算反射光和折射光中,递归跟踪光线时,若直接以交点作为观察原点计算光线,则结果也会出现很多噪点。 如下图所示: 其原因也是因为求光线与球的交点时,得到的t值的精度问题。 计算得到的点,理论上应该是球表面的点,但实际是位于球内,所以计算反射光线时,刚好又与球相交。 计算折射光线时也是同样的原因。 只要在计算光线前,观察原点加上观察方向上的一个小分量作为修正,问题就能解决。 我的程序中是预定义一个小的浮点数SMALLF=0.00001,然后在递归跟踪光线中,SMALLF乘上光线方向,并加到观察点上。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 试验报告 光线 跟踪 实现