smallpt в 50 строк

ray tracing, path tracing, computer graphics

Наглядным примером стохастического алгоритма path tracing является smallpt. В smallpt базовый алгоритм реализован во всего 99 строках кода. Минимальный размер позволяет легко изучать реализацию. Но он может быть ещё меньше, например, 49 строк — как в данной статье. Такой код правда проигрывает в читабельности (и не только), но представляет эзотерический интерес]

weert.cpp

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
struct V {
  double x,y,z;
  V(double u=0, double v=0, double w=0):x(u),y(v),z(w){};
  V operator+(V b){return V(x+b.x,y+b.y,z+b.z);}
  V operator-(V b){return V(x-b.x,y-b.y,z-b.z);}
  V operator*(double k){return V(k*x,k*y,k*z);}
  V operator^(V v){return V(x*v.x,y*v.y,z*v.z);}
  double operator*(V b){return x*b.x+y*b.y+z*b.z;}
  V c(V b){return V(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);}
} Z=V(),M,O=V(50,52,285),*o,ro,D,l,f,dd,sd,gd,n,N,L,c,u,v;
V h(V v){return v*(1/sqrt(v.x*v.x+v.y*v.y+v.z*v.z));}
double A=1e5,B=.999,C=.7,X=81.6,Y=50,Q[]={Y,691.33,X,600,0,0,
  12,12,12,0,0,0,1,0,0,-A+1,Y,X,A,0,0,0,0,0,C,.25,.25,1,0,0,
  A+99,Y,X,A,0,0,0,0,0,.25,.25,C,1,0,0,Y,50.8,-A-25,A,0,0,0,0,
  0,C,C,C,1,0,0,Y,-A+10,X,A,0,0,0,0,0,C,C,C,1,0,0,Y,A+91.6,X,A,
  0,0,0,0,0,C,C,C,1,0,0,27,26.5,47,16.5,0,0,0,0,0,B,B,B,0,1,0,
  73,26.5,78,16.5,0,0,0,0,0,B,B,B,0,0,1},t,tt,d,b,W,K=0.04,F,J;
double r(){return (double)rand()/(double)RAND_MAX;};
double ppm(double x){return pow(x<0?0:x>1?1:x,1/2.2);}
main(int I, char** argv) {
  printf("P3\n480 360\n255\n", F=(1-K),J=1/1.5,W=2*M_PI);
  for (int sw=480,sh=360,S=16384,i=0,s=0,j;i<sw*sh;i++) {
    fprintf(stderr,"\r%.2f%%",(100.*i)/(sw*sh));
    X=sw*.5135/sh,Y=-.5135,A=B=C=0,o=(V*)Q,M=V(1,1,1);
    for (double a=0,U=i%sw,E,P,k,e;a<S;a++,b=r()-r(),U=i%sw+b) {
      ro=O,l=Z,f=M,D=h(V(X*(U/sw-.5),Y*((i*1./sw+b)/sh-.5),-1));
      for (double t=1e3,m=2,r1,r2,q,H,j=0,G;(r2=r())<=m;t=1e3) {
        for (V*ss=(V*)Q;j<8;ss+=5,q=sqrt(r2)) {
          u=ss[0]-ro,b=D*u,d=b*b-u*u+ss[1].x*ss[1].x,r1=r();j++;
          if ((tt=b-sqrt(d>=0?d:1e9))>1e-4 && tt<t) t=tt,o=ss;
          if ((tt=b+sqrt(d>=0?d:1e9))>1e-4 && tt<t) t=tt,o=ss;
        }
        n=h((ro=ro+D*t)-*o),N=(n*D)<0?n:n*-1,l=l+f^o[2],c=o[3];
        m=fmax(c.x,fmax(c.y,c.z)),r1*=W,c=c*(1/m),f=f^c,d=D*N,
        u=h((fabs(N.x)>.1?V(0,1):V(1)).c(N)),k=(G=n*N>0)?J:1.5,
        dd=h(u*cos(r1)*q+N.c(u)*sin(r1)*q+N*sqrt(1-r2)),H=d*d,
        H=1-k*k*(1-H),v=h(D*k-n*((G?1:-1)*(d*k+sqrt(H)))),
        gd=sd=D-n*2*(n*D),I=H>=0,E=K+F*pow(1-(G?-d:v*n),5),
        P=.25+E/2,f=I?r2<P?f*E*(1/P):f*((1-E)/(1-P)):f,L=o[4],
        gd=I?r2<P?sd:v:gd,D=dd*L.x+sd*L.y+gd*L.z;j=0;
      }
      l=l*(1./S),A+=fmin(l.x,1),B+=fmin(l.y,1),C+=fmin(l.z,1);
    }
    printf("%.0f %.0f %.0f ", V(ppm(A),ppm(B),ppm(C))*255);
  }
}

Синтезируемое изображение

$ g++ -O3 weert.cpp; ./a.out > r.ppm

Наблюдения

Код вмещается в 64-колоночное окно без прокрутки и насчитывает 49 строк:

Вычислительная часть кода напоминает brainfuck]

Пожалуй, компактификация выполнена не очень творчески, поскольку не было предложено качественно новых компактных или аппроксимирующих альтернатив относительно исходника, но были лишь оптимизированы существующие. Возможно, что либо размер может быть ещё уменьшен, либо код может быть упрощён.

 

Ссылки

 

До встречи в виртуальной реальности, визуализированной с помощью лучших алгоритмов растеризации!

 

shitpoet@gmail.com

 



 

free hit counters