光線追蹤試玩

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

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