经过LRJ大大的指点,我今天花了一天时间写成了我第一个光线追踪!!
先暂时上点成果演示,因为我还想继续添加一点新元素,比如加入球体,贴图什么的。
首先上一个有镜子的:
然后,再上一个有折射的
(还有全反射现象哦!)
呃 ~~~锯齿是不是非常严重?去偷学了个抗锯齿的技能,还是有一点效果的拉:
还有这个,抗锯齿的对比(代码写的好丑。。渲染下面这个图就用了10分钟)
好吧,承认我抗锯齿写的很渣。。。。。
接下来计划添加贴图,还有加入球体。(椭球有没有这玩意?)
代码(各种三维~~其实比杀菌计划还要短一点呢)
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#define maxdepth 2
#define e 1e-8
using namespace std;
struct P{double x,y,z;};
P operator +(P a,P b) {return (P){a.x+b.x,a.y+b.y,a.z+b.z};}
P operator -(P a,P b) {return (P){a.x-b.x,a.y-b.y,a.z-b.z};}
P operator *(P a,double b) {return (P){a.x*b,a.y*b,a.z*b};}
P operator /(P a,double b) {return a*(1/b);}
P operator *(P a,P b) {return (P){a.y*b.z-a.z*b.y,a.z*b.x-b.z*a.x,a.x*b.y-a.y*b.x};}
double operator /(P a,P b) {return a.x*b.x+a.y*b.y+a.z*b.z;}
double mo(P a) {return sqrt(a.x*a.x+a.y*a.y+a.z*a.z);}
int C(double a) {return (a<-e)?-1:a>e;}
struct SJ{P p[4],X,Y,Z,color;double refl,refr,indx;};
struct RAY{P a,b;};
P change(P a,SJ b) {return (P){a/b.X,a/b.Y,a/b.Z};}
RAY get_f(SJ s,RAY r) {
RAY ans;
ans.a=(P){1e50,1e50};
if (s.indx>1e3) return ans;
P a=change(r.a,s);
P b=change(r.b,s);
if (!C(b.z)) return ans;
double dt=(s.p[0].z-a.z)/b.z;
if (C(dt)<=0) return ans;
a=a+(b*dt);
for (int i=0;i<3;i++) {
P tt=(s.p[i+1]-s.p[i])*(a-s.p[i]);
if (C(tt.z)<0) return ans;
};
b.z=-b.z;
P dx=(P){1,0,0};
P dy=(P){0,1,0};
P dz=(P){0,0,1};
dx=change(dx,s);
dy=change(dy,s);
dz=change(dz,s);
dx=dx/(mo(dx));
dy=dy/(mo(dy));
dz=dz/(mo(dz));
ans.a=(P){a/dx,a/dy,a/dz};
ans.b=(P){b/dx,b/dy,b/dz};
return ans;
}
RAY get_z(SJ s,RAY r,double zr) {
RAY ans;
ans.a=(P){1e50,1e50};
P a=change(r.a,s);
P b=change(r.b,s);
if (!C(b.z)) return ans;
double dt=(s.p[0].z-a.z)/b.z;
if (C(dt)<=0) return ans;
double gm;
if (C(zr-s.indx)) gm=mo(b)*s.indx;
else gm=mo(b)/s.indx;
a=a+(b*dt);
for (int i=0;i<3;i++) {
P tt=(s.p[i+1]-s.p[i])*(a-s.p[i]);
if (C(tt.z)<0) return ans;
};
P dx=(P){1,0,0};
P dy=(P){0,1,0};
P dz=(P){0,0,1};
dx=change(dx,s);
dy=change(dy,s);
dz=change(dz,s);
dx=dx/(mo(dx));
dy=dy/(mo(dy));
dz=dz/(mo(dz));
gm=gm*gm-b.x*b.x-b.y*b.y;
if (C(gm)<=0) return ans;
gm=sqrt(gm);
if (b.z>0) b.z=gm; else b.z=-gm;
ans.a=(P){a/dx,a/dy,a/dz};
ans.b=(P){b/dx,b/dy,b/dz};
return ans;
}
vector<SJ> s(0);
SJ getclose(RAY a) {
SJ b;
b.indx=1e9;
P c,d=(P){1e30,1e30};
for (int i=0;i<(int)s.size();i++) {
c=get_f(s[i],a).a;
if (mo(c-a.a)<mo(d-a.a)) b=s[i],d=c;
};
return b;
}
SJ makeSJ(P a,P b,P c) {
SJ h;
h.p[0]=h.p[3]=a;
h.p[1]=b, h.p[2]=c;
h.Z=(b-a)*(c-a);
h.X=(b-a)*h.Z;
h.Y=h.Z*h.X;
h.X=h.X/(mo(h.X));
h.Y=h.Y/(mo(h.Y));
h.Z=h.Z/(mo(h.Z));
for (int i=0;i<4;i++) h.p[i]=change(h.p[i],h);
return h;
}
P sun,sunl;
double amb;
P get_point_color(SJ a,P b) {
RAY r=(RAY){b,sun-b};
r.b=r.b/(mo(r.b));
P x=get_f(getclose(r),r).a;
double l;
if (C(mo(b-x)-mo(sun-b))>=0) {
l=abs(a.Z/r.b);
} else l=0;
l=amb+(1-amb)*l;
a.color.x*=sunl.x;
a.color.y*=sunl.y;
a.color.z*=sunl.z;
return a.color*l;
}
P trace_ray(int depth, RAY r,double zr) {
P point_color=(P){0,0,0},reflect_color=(P){0,0,0},refract_color=(P){0,0,0};
if (mo(r.a)>1e20) return point_color;
SJ i=getclose(r);
if(i.indx<1e3) {
double refl=i.refl;
double refr=i.refr;
P x=get_f(i,r).a;
point_color=get_point_color(i,x) * (1-refl-refr);
if(depth<maxdepth && C(refl)>0)
reflect_color=trace_ray(depth+1, get_f(i,r),zr) * refl;
if(depth<maxdepth && C(refr)>0)
refract_color=trace_ray(depth+1, get_z(i,r,zr),(!C(zr-1))?i.indx:1) * refr;
}
return point_color+reflect_color+refract_color;
}
int main() {
freopen("N_input_6.txt","r",stdin);
freopen("image.txt","w",stdout);
s.clear();
int n;
scanf("%d",&n);
while (n--) {
int np;
vector<P> p(0);
scanf("%d",&np);
while (np--) {
P h;
scanf("%lf%lf%lf",&h.x,&h.y,&h.z);
p.push_back(h);
};
int mp;
scanf("%d",&mp);
for (int i=1;i<=mp;i++) {
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
s.push_back(makeSJ(p[a],p[b],p[c]));
};
P color;
scanf("%lf%lf%lf",&color.x,&color.y,&color.z);
double refl,refr,idx;
scanf("%lf%lf%lf",&refl,&refr,&idx);
for (int i=1;i<=mp;i++) {
s[s.size()-i].color=color;
s[s.size()-i].refl=refl;
s[s.size()-i].refr=refr;
s[s.size()-i].indx=idx;
};
};
scanf("%lf%lf%lf",&sun.x,&sun.y,&sun.z);
scanf("%lf",&amb);
scanf("%lf%lf%lf",&sunl.x,&sunl.y,&sunl.z);
int np;
scanf("%d",&np);
while (np--) {
P cs,ct,cu;
scanf("%lf%lf%lf",&cs.x,&cs.y,&cs.z);
scanf("%lf%lf%lf",&ct.x,&ct.y,&ct.z);
scanf("%lf%lf%lf",&cu.x,&cu.y,&cu.z);
ct=ct-cs;
P cl=ct*cu;
cu=cu/mo(cu);
cl=cl/mo(cl);
ct=ct/mo(ct);
double fov;
int w,d;
scanf("%lf",&fov);
scanf("%d%d",&w,&d);
printf("%d %d\n",w,d);
double ld=tan(fov/180*M_PI/2)/(w*.5);
P rs=cl*ld,ds=cu*(-ld);
P ss=ct-(rs*(w*.5))-(ds*(d*.5));
for (int i=1;i<=d;i++) {
for (int j=1;j<=w;j++) {
if (!((i*w+j)%500))fprintf(stderr,"loading.... %.2lf%%\n",((i-1.)*w+j)/(d*w)*100);
P ns=ss+(rs*(j-.5))+(ds*(i-.5));
RAY go=(RAY){cs,ns};
P cl=trace_ray(0,go,1);
printf("%02x%02x%02x ",(int)(cl.x*255),(int)(cl.y*255),(int)(cl.z*255));
//printf("%lf %lf %lf ",cl.x,cl.y,cl.z);
};
printf("\n");
};
};
return 0;
}