光線追蹤——最終版

今天又泡了一天的時間在光線追蹤上,不過顯然,收穫頗多。

首先是花了半個小時推球體反射折射的式子,然後改了改光源的位置,畫出的第一幅圖是這樣的:



完全被嚇了一跳,爲什麼突然變得這麼好了?(可以對比昨天的圖)

唧唧提醒了我,因爲我把光源往下拉了,所以導致上方牆壁出現光暈,增加了真實感,於是乎,我加上了光暈,光暈的亮度隨着距離線性遞減:



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;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章