急!!求高手改程序!光线追踪算法的实现,用vc++下的opengl!
我想写一个画两个不透明的球的光线追踪算法,但不知道哪里出了问题,画出来的是黑白相间的直线条纹。求高手帮忙看一下!不胜感谢!
//下面针对反射实现光线跟踪算法
#include "stdafx.h"
//*******************************************************************
//三维向量的定义、两种构造函数及运算符+、-、*、/的重载
class vector
{
public:
int x;
int y;
int z;
vector(){x=0;y=0;z=0;}
vector(float a,float b,float c){x=a;y=b;z=c;}
friend vector operator +(vector &c1,vector &c2)//重载+使其能完成两个向量的求和
{
return vector(c1.x+c2.x,c1.y+c2.y,c1.z+c2.z);
}
friend float operator *(vector &c1,vector &c2)//重载*使其能完成两个向量的点积
{
return c1.x*c2.x+c1.y*c2.y+c1.z*c2.z;
}
friend vector operator *(vector &c1,float a)//重载*使其能完成向量和数的相乘
{
return vector(c1.x*a,c1.y*a,c1.z*a);
}
friend vector operator /(vector &c1,float a)//重载/使其能完成向量和数值的除法
{
return vector(c1.x/a,c1.y/a,c1.z/a);
}
friend vector operator -(vector &c1,vector &c2)//重载-使其能完成向量相减
{
return vector(c1.x-c2.x,c1.y-c2.y,c1.z-c2.z);
}
};
//颜色定义、两种构造函数及运算符+、-的重载
class color
{
public:
float R;
float G;
float B;
color(){R=0;G=0;B=0;}//黑
color(float a,float b,float c){R=a;G=b;B=c;}
friend color operator +(color &c1,color &c2)//重载+使其能完成两个向量的求和
{
return color(c1.R+c2.R,c1.G+c2.G,c1.B+c2.B);
}
friend color operator -(color &c1,color &c2)
{
return color(c1.R-c2.R,c1.G-c2.G,c1.B-c2.B);
}
friend color operator *(color &c1,float z)
{
return color(c1.R*z,c1.G*z,c1.B*z);
}
friend color operator *(color &c,vector &v)
{
return color(c.R*v.x,c.G*v.y,c.B*v.z);
}
friend color operator /(color &c1,float z)
{
return color(c1.R/z,c1.G/z,c1.B/z);
}
};
//光线定义:光色、传播矢量、起点
class light//光线的定义
{
public:
color lightcolor;//光色
vector L;//传播方向的单位矢量
vector loc;//“相对光源”位置(起点位置)
};
//单色光滑球体的定义:球心、半径、材料的光反射属性
class sphere
{
public:
vector heart;//球心位置
float r;//半径
float Ka;//环境光反射属性
float Kdr;//漫反射光(红光分量)
float Kdg;
float Kdb;
float Ks;//镜面反射
float light_n;//高光系数
sphere(float hx,float hy,float hz,float rl
,float ka,float kdr,float kdg,float kdb,float ks,float n)
{
heart.x=hx;heart.y=hy;heart.z=hz;r=rl;Ka=ka;
Kdr=kdr;Kdr=kdr;Kdg=kdg;Kdb=kdb;Ks=ks;light_n=n;
}
};
///////////////////////////////////////////////////////////////////////////
//求两点间的距离
float distance(vector c1,vector c2)
{
return sqrt((c1-c2)*(c1-c2));
}
//求两点间的单位矢量
vector view(vector c,vector v)
{
return (v-c)/sqrt((v-c)*(v-c));
}
//求球体a和光线v的交点
vector intersection(sphere a,light v)
{
float b=v.L*(v.loc-a.heart)*2;
float c=(v.loc-a.heart).x*(v.loc-a.heart).x+(v.loc-a.heart).y*(v.loc-a.heart).y+(v.loc-a.heart).z*(v.loc-a.heart).z-a.r*a.r;
float d=b*b-4*c;//判断是否有交点的量
if(d<0)
return v.loc;//无交点
if(d==0)
if(b<=0)
return v.loc-v.L*b/2;//R=V-b/2*d即为光线与球的交点。
else
return v.loc;//交点不在光线上
if(d>0)
{
float t1=(sqrt(b*b-4*c)-b)/2;
float t2=(-b-sqrt(b*b-4*c))/2;
if(t1<0&&t2<0)
return v.loc;//交点不在光线上
else
{//交点为R(t0)
if(t1<0)
return v.loc+v.L*t2;
if(t2<0)
return v.loc+v.L*t1;
if(t1>=0&&t2>=0)
{
int t0=t1>t2?t2:t1;
return v.loc+v.L*t0;
}
}
}
}
vector intersection(sphere a,vector loc,vector L)
{
float b=L*(loc-a.heart)*2;
float c=(loc-a.heart).x*(loc-a.heart).x+(loc-a.heart).y*(loc-a.heart).y+(loc-a.heart).z*(loc-a.heart).z-a.r*a.r;
float d=b*b-4*c;//判断是否有交点的量
if(d<0)
return loc;//无交点
if(d==0)
if(b<=0)
return loc-L*b/2;//R=V-b/2*d即为光线与球的交点。
else
return loc;//交点不在光线上
if(d>0)
{
float t1=(sqrt(b*b-4*c)-b)/2;
float t2=(-b-sqrt(b*b-4*c))/2;
if(t1<0&&t2<0)
return loc;//交点不在光线上
else
{//交点为R(t0)
if(t2<0)
return loc+L*t1;
if(t1<0)
return loc+L*t2;
if(t1>=0&&t2>=0)
{
int t0=t1>t2?t2:t1;
return loc+L*t0;
}
}
}
}
//求交点的单位法矢量
vector normals(sphere a,light v)
{
vector S=intersection(a,v);
return (S-a.heart)/a.r;
}
vector normals(sphere a,vector loc,vector L)
{
vector S=intersection(a,loc,L);
return (S-a.heart)/a.r;
}
vector normals(sphere a,vector cro)
{
return (cro-a.heart)/a.r;
}
//求反射光线(单位?)
vector reflection(sphere a,light v)
{
vector N=normals(a,v);
return N*(N*v.L)*2-v.L;
}
vector reflection(sphere a,vector loc,vector L)
{
vector N=normals(a,loc,L);
return N*(N*L)*2-L;
}
//阴影测试算法(球体a,光源点s,交点c),返回为光纤与某个球体的焦点的个数
float shadow(sphere a,vector s,vector c)
{
vector l=view(c,s);//c到s的单位方向矢量
float b=l*(s-a.heart)*2;
float e=(s-a.heart).x*(s-a.heart).x+(s-a.heart).y*(s-a.heart).y+(s-a.heart).z*(s-a.heart).z-a.r*a.r;
float d=b*b-4*e;//判断是否在阴影范围内的量
if(d>0)
{
float t1=(sqrt(b*b-4*e)-b)/2;
float t2=(-b-sqrt(b*b-4*e))/2;
if(t1<0&&t2<0)
return 0;//交点不在光线上
else
if(t1<0||t2<0)
return 1;
else
return 2;
}
if(d==0)
if(b<=0)
return 1;
else
return 0;
if(d<0)
return 0;
}
//在存在两个交点的情况下选取较为靠前且不同于视点的交点的函数
vector choose(vector c1,vector c2,vector v)
{
if(c1.x!=v.x&&c2.x!=v.x)//两个交点均不同于视点
if(c1.z>c2.z)
return c1;
else
return c2;
else
if(c1.x!=v.x)//如果c1点不同
return c1;
else
return c2;
}
//在已知一个交点的情况下判断其所在的球体
sphere choosesph(vector cro,sphere s1,sphere s2)
{
if((cro-s1.heart)*(cro-s1.heart)==(s1.r*s1.r))
return s1;
else
return s2;
}
//////////////////////////////////////////////////////////////////////////////
vector viewpoint(0,0,100);vector lightsource(-300,200,80);//视点、光源坐标位置
color backcolor(0,0,0);//定义背景色
color acolor(0.5,0.5,0.5);//定义环境光色
color pcolor(1,1,1);//定义光源的光色
//定义两个球体
sphere Sphere1(-10,10,-50,20,0.2,0.6,0.1,0.3,0.2,2);
sphere Sphere2(100,100,-100,40,0.7,0.7,0.3,0.5,0.1,4);
int depth=5;//追踪深度
///////////////////////////////////////////////////////////////////////////////
//光线追踪算法,
color TraceLight(vector start,vector L,int depth,color &c)
{
vector R,N,Rs,Ls;
vector cross1=intersection(Sphere1,start,L);
vector cross2=intersection(Sphere2,start,L);
if((cross1.x==cross2.x==start.x)&&(cross1.y==cross2.y==start.y)&&(cross1.z==cross2.z==start.z))//如果没有符合要求的交点
c=backcolor;
else//开始追踪
{
cross1=choose(cross1,cross2,start);//选择一个点
sphere Sphere3=choosesph(cross1,Sphere1,Sphere2);//选择该点所在的球体
//阴影判断//在阴影范围内则该点的当前光强为0;
//若不在阴影范围内则采用phone模型得到光源在该点产生的局部光颜色
int cronum=shadow(Sphere1,lightsource,cross1)+shadow(Sphere2,lightsource,cross1);//交点总数
if(cronum>1)
{c.R=0;c.G=0;c.B=0;}
else
{
vector kd(Sphere3.Kdr,Sphere3.Kdg,Sphere3.Kdb);
N=normals(Sphere3,cross1);
Ls=view(lightsource,cross1);
Rs=reflection(Sphere3,lightsource,Ls);
c=acolor*Sphere3.Ka+pcolor*kd*(N*Ls)+pcolor*(powf((Rs*N),Sphere3.light_n))*Sphere3.Ks;
}
//如果层数大于1则追踪求反射光线并追踪
if(depth>1)
{
R=reflection(Sphere3,start,L);
color cr;
cr=TraceLight(cross1+vector(1,1,1),R,depth-1,cr);
c=c+cr;
}
}//追踪结束
return c;
}
//初始化
void myInit()
{
glClearColor(0,0,0,0);//设置背景颜色为黑色;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-400,400,-300,300,400,-400);//坐标设置
}
//显示函数
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glBegin(GL_POINTS);
for(float i=-199;i<200;i=i+1)
for(float j=-199;j<200;j=j+1)
{
vector screen=vector(i,j,0);
vector vL=view(viewpoint,screen);
color cs=TraceLight(viewpoint,vL,depth,cs);
glColor3f(cs.R,cs.G,cs.B);
glVertex3f(screen.x,screen.y,screen.z);
}
glEnd();
glFlush();
}
//主函数
int main(int argc,char* argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(800,600);
glutInitWindowPosition(0,0);
glutCreateWindow("123");
myInit();
glutDisplayFunc(myDisplay);
glutMainLoop();
}
[解决办法]
楼主可以到我的blog去看看一篇管线追踪的文章