今天又泡了一天的時間在光線追蹤上,不過顯然,收穫頗多。
首先是花了半個小時推球體反射折射的式子,然後改了改光源的位置,畫出的第一幅圖是這樣的:
完全被嚇了一跳,爲什麼突然變得這麼好了?(可以對比昨天的圖)
唧唧提醒了我,因爲我把光源往下拉了,所以導致上方牆壁出現光暈,增加了真實感,於是乎,我加上了光暈,光暈的亮度隨着距離線性遞減:
ohNO,這個光暈真他媽醜,於是乎我改成了餘弦函數:
嗯,相當的不錯!
接下來我不斷的修改參數:
嗯,鋸齒很嚴重嘛。。抗鋸齒抗鋸齒抗鋸齒~~~
大家可以來找找茬,上面兩幅圖片一個是我允許反射折射遞歸深度爲4的,一個是6的。
調參數調來調去花了2個小時,接下來又到了碼代碼的時候,完成貼圖任務!
苦逼的是圖像文件怎麼讀入啊。。我只會輸出不會讀入啊,問了問LRJ老師,又查了查wiki,最後翻到了FHQ的代碼,總算是知道BMP文件怎麼讀入了。
貼出來的第一張圖!十分驚悚!(誒,這算不算侵犯肖像權呢?)
這幅圖就可以清晰地看到折射現象了,右邊的玻璃球中呈現出來的倒置的實相。
第一次貼圖成功了,於是乎,我——————
加了個background,不過圖片太維和了= =!
最後,做了個最滿意的高清壁紙!1440*900!(OH NO,被壓縮了!看上去像蒙了一層灰一樣。。)
finally,貼出冗長的代碼
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#define maxdepth 6
#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;}
double sqr(double x) {return x*x;}
struct SJ{P p[4],X,Y,Z,o,color;int kind;double R,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};}
double ttt,gr;
struct BMP {
#define a(i,j,k) data[((i)*((W*3+3)&~3))+(j)*3+(k)]
int W,H;
unsigned char* data;
int readLong(FILE *fin){
int b0,b1,b2,b3;
b0=fgetc(fin);b1=fgetc(fin);b2=fgetc(fin);b3=fgetc(fin);
return b0 | (b1<<8) | (b2<<16) | (b3<<24);
}
void build(char *Fname) {
FILE *fin=fopen(Fname,"rb");
if (!fin){fprintf(stderr,"error\n");return;}
fseek(fin,0x12,0);
W=readLong(fin);
H=readLong(fin);
fseek(fin,0x36,0);
data=new unsigned char[((W*3+3)&~3)*H];
fread(data,1,((W*3+3)&~3)*H,fin);
for (int i=0;H-1-i>=i;i++){
for (int j=0;j<W;j++){
swap(a(i,j,0),a(H-1-i,j,2));
swap(a(i,j,1),a(H-1-i,j,1));
swap(a(i,j,2),a(H-1-i,j,0));
};
};
fclose(fin);
}
P BMPcolor(double x,double y) {
int i=(int)(x*H),j=(int)(y*W);
if (i<0) i=0;
if (j<0) j=0;
if (i>=H) i=H-1;
if (j>=W) j=W-1;
return (P){a(i,j,0)/255.,a(i,j,1)/255.,a(i,j,2)/255.};
}
};
vector<BMP> pic(0);
RAY get_f(SJ s,RAY r) {
RAY ans;
ans.a=(P){1e50,1e50};
if (s.indx>1e3) return ans;
if (!s.kind) {
r.b=r.b/(mo(r.b));
double dt=(r.b/s.o)-(r.b/r.a);
P md=r.a+(r.b*dt);
double dis=mo(md-s.o);
if (C(dis-s.R)>=0) return ans;
double kd=sqrt(s.R*s.R-dis*dis);
if (C(dt+kd)<=0) return ans;
if (C(dt-kd)>0) ans.a=md-(r.b*kd);
else ans.a=md+(r.b*kd);
P f=ans.a-s.o;
f=f/(mo(f));
dt=r.b/f;
ans.b=r.b-(f*(dt*2));
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+!!(s.kind<0));i++) {
P tt=(s.p[(i+1)&3]-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};
if (!s.kind) {
r.b=r.b/(mo(r.b));
double dt=(r.b/s.o)-(r.b/r.a);
P md=r.a+(r.b*dt);
double dis=mo(md-s.o);
if (C(dis-s.R)>=0) return ans;
double kd=sqrt(s.R*s.R-dis*dis);
if (C(dt+kd)<=0) return ans;
if (C(dt-kd)>0) ans.a=md-(r.b*kd);
else ans.a=md+(r.b*kd);
P f=s.o-ans.a;
f=f/(mo(f));
dt=r.b/f;
double gm;
if (C(zr-s.indx)) gm=mo(r.b)*s.indx;
else gm=mo(r.b)/s.indx;
gm=gm*gm-(sqr(mo(r.b))-dt*dt);
if (C(gm)<=0) {ans.a=(P){1e50,1e50};return ans;}
gm=sqrt(gm);
if (dt<0) gm=-gm;
ans.b=r.b+(f*(gm-dt));
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;
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+!!(s.kind<0));i++) {
P tt=(s.p[(i+1)&3]-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,double &light,double md) {
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;
double idd=mo(c-a.a);
if (C(idd-md)<0) light*=s[i].refr;
if (idd<mo(d-a.a)) b=s[i],d=c;
};
return b;
}
SJ makeSJ(P a,P b,P c) {
SJ h;
h.kind=1;
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));
double l=1,sundis=mo(sun-b);
get_f(getclose(r,l,sundis),r).a;
P f=a.Z;
if (!a.kind) {
f=b-a.o;
f=f/(mo(f));
} else
if (a.kind<0) {
P nj=(P){b/a.X,b/a.Y,b/a.Z};
P fx=a.p[1]-a.p[0];
P fy=a.p[3]-a.p[0];
double mx=mo(fx),my=mo(fy);
fx=fx/mx,fy=fy/my;
nj=nj-a.p[0];
double dx=(nj.x*fy.y-nj.y*fy.x)/(fx.x*fy.y-fx.y*fy.x)/mx;
double dy=(nj.x*fx.y-nj.y*fx.x)/(fx.y*fy.x-fx.x*fy.y)/my;
a.color=pic[-1-a.kind].BMPcolor(dx,dy);
};
l*=pow(abs(f/r.b),3);
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,ttt,ttt);
P x;
if(i.indx<1e3) {
double refl=i.refl;
double refr=i.refr;
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;
} else x=(P){1e30,1e30};
P ncl=point_color+reflect_color+refract_color;
r.b=r.b/(mo(r.b));
double sr=(r.b/r.a),dt=(r.b/sun)-sr;
P jd=r.a+(r.b*dt);
double rd=mo(jd-sun);
if (rd<gr && dt>e && (mo(x)>1e30 || dt<((r.b/x)-sr))) {
double l=cos(rd/gr*M_PI)/2+0.5;
ncl=(ncl*(1-l))+(sunl*l);
};
return ncl;
}
P shot(P s,P t) {
RAY r=(RAY){s,t};
return trace_ray(0,r,1);
}
int main() {
freopen("N_input_0.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);
for (int i=1;i<=np;i++) {
P h;
scanf("%lf%lf%lf",&h.x,&h.y,&h.z);
p.push_back(h);
};
int mp;
scanf("%d",&mp);
if (np==1) {
SJ h;
h.kind=0;
h.o=p[0];
scanf("%lf",&h.R);
s.push_back(h);
} else
if (np==4 && mp==1) {
BMP picture;
char Fname[100];
scanf("%s",Fname);
picture.build(Fname);
pic.push_back(picture);
SJ h=makeSJ(p[0],p[1],(p[2]+p[1])-p[0]);
h.p[3]=change(p[2],h);
h.kind=-((int)pic.size());
s.push_back(h);
} else
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%lf",&gr,&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));
P cl=shot(cs,ns);
if (0) {
cl=cl+shot(cs,ns+(rs*.4));
cl=cl+shot(cs,ns-(rs*.4));
cl=cl+shot(cs,ns+(ds*.4));
cl=cl+shot(cs,ns-(ds*.4));
cl=cl/5;
};
printf("%02x%02x%02x ",(int)(cl.x*255),(int)(cl.y*255),(int)(cl.z*255));
};
printf("\n");
};
};
return 0;
}