试验报告光线跟踪的实现.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=1color=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=1Rayrtest(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乘上光线方向,并加到观察点上。
T=t1;
reslut=true;
inp=true;
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=1color=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=1Rayrtest(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乘上光线方向,并加到观察点上。
T=t2;
returnreslut;
2.光线平面相交
首先平面的法向量N与光线方向向量V点乘,如果结果不为0,则光线与平面有交点,计算出对应交点的t值
具体实现如下
boolPlane:
vec3ftmp=r.getOrigin()-_center;
floatcosV_N=-dot(r.getDirection(),_normal);
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=1color=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=1Rayrtest(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乘上光线方向,并加到观察点上。
T=t;
四.慢反射光的计算
漫反射的计算公式为
,为了实现方便,我将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;
六.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()为镜面反射系数。
七.反射光的计算
反射光线的计算公式为:
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()是物体的反射系数。
八.折射光的计算
根据折射定理可以得到公式
其中T为折射光线的方向向量,I为入射光线,n为交点处的法向量,
,
。
我的程序中,物体的折射率事先给定。
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;
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是入射光向量。
左边大球后面有一个红色小球,右边打球后面有四个蓝色小球。
左边的球透明系数为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乘上光线方向,并加到观察点上。
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乘上光线方向,并加到观察点上。
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乘上光线方向,并加到观察点上。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1