蒙特卡罗光线追踪算法 smallpt: Global Illumination in 99 lines of C++

1.光的基本传递模型

(1)在一个要渲染的场景中,我们认为光能由预先指定的光源发出,然后我们以光线来描述光能的传递过程,当整个场景中的光能信息被我们计算出来后,我们收集这些信息转化为顶点的亮度。   

(2)光线经过物体表面可以产生反射和漫反射,光线透过物体可以产生折射和散射。具体产生哪种出射效果,依据物体的表面属性而定。物体的表面一般不会是理想的某种单一属性的表面,表面可以同时存在反射,折射,漫反射等多种属性,各种属性按一定比例混合之后才是其表面反射模型。   

(3)一点的在某一个视线方向上的光亮度=该点在该方向的自身发光亮度+半球入射光能在该方向所产生的反射光亮度.  

(4) 关于散射,高度真实的散射是一个很难模拟的物理过程,一般在渲染中都不会采用过于复杂的物理模型来表示散射,而是采用一些取巧的办法来计算散射。   

(5) 在常见的渲染中,有两种效果很难模拟,但是它们会使人眼觉得场景更真实。   

[1]color bleeding :入射光为漫反射,受光表面属性为漫反射,出射光是漫反射。比如把一本蓝色的纸制的书靠近白色的墙,墙上会有浅浅的蓝晕。   

[2]caustics:入射光为镜面反射或折射,受光表面属性为漫反射,出射光是漫反射。比如把一个装了红色葡萄酒的酒杯放在木桌上面,会有光透过杯中的酒在桌上形成一块很亮的红色区域。

2.蒙特卡罗光线追踪

(1)蒙特卡罗光线追踪对逆向光线追踪模型进行改进,其中最大的区别在于把概率模型引入光线追踪。逆向光线追踪中物体的表面材质很单一。引入俄罗斯赌盘轮,可以设定漫反射、镜面反射、甚至折射的概率。丰富表面材质的显示每个像素点只采样一条光线计算出的颜色,正确率不高。引入蒙特卡罗可以多次采样求平均,优化渲染结果。

(2)对传统的逆向光线追踪的改进   

传统的逆向光线追踪算法有两个突出的缺点,就是表面属性的单一,和不考虑漫反射。我们不难通过模型的修正来缓解这两个问题。我们首先认为一个表面的属性可以是混合的,比如它有20%的成分是反射,30%的成分是折射,50%的成分是漫反射。这里的百分比可以这样理解,当一根光线打在该表面后,它有20%的概率发生反射,30%的概率发生折射,50%的概率发生漫反射。然后我们通过多次计算光线跟踪,每次按照概率决定光线的反射属性,这样在就把漫反射也考虑了进去。

具体的算法如下:   

①从视点出发,经过投影屏幕上的每一个像素向场景发射一根虚拟的光线。   

②当光线与景物相交时按照俄罗斯轮盘赌规则决定他的反射属性。   

③根据不同的反射属性继续跟踪计算,直到正常结束或者异常结束。如果反射的属性为漫反射,则随机选择一个反射方向进行跟踪。   

④重复前面的过程,把每次渲染出来的贴图逐像素叠加混合,直到渲染出的结果达到满意程度。

该方法是一种比较简易的基于物理模型的渲染,其本质就是通过大量的随机采样来模拟半球积分。这种方法在光照细节上可以产生真实度很高的图像,但是图像质量有比较严重的走样,而且效率极其低下。

3.99行C++代码实现蒙特卡罗光线追踪算法

#include <math.h>   // smallpt, a Path Tracer by Kevin Beason, 2008
#include <stdlib.h> // Make : g++ -O3 -fopenmp smallpt.cpp -o smallpt
#include <stdio.h>  //        Remove "-fopenmp" for g++ version < 4.2 #ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#include <math.h>
#else
#include <cmath>
#endif // _USE_MATH_DEFINESdouble erand48 (unsigned short xsubi[3]) {return rand() / (double)RAND_MAX;
}struct Vec {        // Usage: time ./smallpt 5000 && xv image.ppm double x, y, z;                  // position, also color (r,g,b) Vec(double x_=0, double y_=0, double z_=0){ x=x_; y=y_; z=z_; } Vec operator+(const Vec &b) const { return Vec(x+b.x,y+b.y,z+b.z); } Vec operator-(const Vec &b) const { return Vec(x-b.x,y-b.y,z-b.z); } Vec operator*(double b) const { return Vec(x*b,y*b,z*b); } Vec mult(const Vec &b) const { return Vec(x*b.x,y*b.y,z*b.z); } Vec& norm(){ return *this = *this * (1/sqrt(x*x+y*y+z*z)); } double dot(const Vec &b) const { return x*b.x+y*b.y+z*b.z; } // cross: Vec operator%(Vec&b){return Vec(y*b.z-z*b.y,z*b.x-x*b.z,x*b.y-y*b.x);}
}; //ray 射线
struct Ray { Vec o, d; Ray(Vec o_, Vec d_) : o(o_), d(d_) {} };
enum Refl_t { DIFF, SPEC, REFR };  // material types, used in radiance()
struct Sphere { double rad;       // radius Vec p, e, c;      // position, emission, color Refl_t refl;      // reflection type (DIFFuse, SPECular, REFRactive) Sphere(double rad_, Vec p_, Vec e_, Vec c_, Refl_t refl_): rad(rad_), p(p_), e(e_), c(c_), refl(refl_) {} double intersect(const Ray &r) const { // returns distance, 0 if nohit Vec op = p-r.o; // Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0 double t, eps=1e-4, b=op.dot(r.d), det=b*b-op.dot(op)+rad*rad; if (det<0) return 0; else det=sqrt(det); return (t=b-det)>eps ? t : ((t=b+det)>eps ? t : 0); }
}; //球体 diff漫反射  spec镜面反射  refr反射和折射
Sphere spheres[] = {//Scene: radius, position, emission, color, material Sphere(1e5, Vec( 1e5+1,40.8,81.6), Vec(),Vec(.75,.25,.25),DIFF),//Left Sphere(1e5, Vec(-1e5+99,40.8,81.6),Vec(),Vec(.25,.25,.75),DIFF),//Rght Sphere(1e5, Vec(50,40.8, 1e5),     Vec(),Vec(.75,.75,.75),DIFF),//Back Sphere(1e5, Vec(50,40.8,-1e5+170), Vec(),Vec(1,1,1)*.999,DIFF),//Frnt Sphere(1e5, Vec(50, 1e5, 81.6),    Vec(),Vec(.75,.75,.75),DIFF),//Botm Sphere(1e5, Vec(50,-1e5+81.6,81.6),Vec(),Vec(.75,.75,.75),DIFF),//Top Sphere(16.5,Vec(27,16.5,47),       Vec(),Vec(1,1,1)*.999, SPEC),//Mirr Sphere(16.5,Vec(73,16.5,78),       Vec(),Vec(1,1,1)*.999, REFR),//GlasSphere(10,Vec(40,50,100),       Vec(),Vec(.75,.75,.75), DIFF),//DIFFSphere(600, Vec(50,681.6-.27,81.6),Vec(12,12,12),  Vec(), DIFF) //Lite
}; //遍历所有的球,求交点
inline double clamp(double x){ return x<0 ? 0 : x>1 ? 1 : x; }
inline int toInt(double x){ return int(pow(clamp(x),1/2.2)*255+.5); }
inline bool intersect(const Ray &r, double &t, int &id){ double n=sizeof(spheres)/sizeof(Sphere), d, inf=t=1e20; for(int i=int(n);i--;) if((d=spheres[i].intersect(r))&&d<t){t=d;id=i;} return t<inf;
} //光线跟踪递归函数
Vec radiance(const Ray &r, int depth, unsigned short *Xi){ double t;                               // distance to intersection int id=0;                               // id of intersected object if (!intersect(r, t, id)) return Vec(); // if miss, return black const Sphere &obj = spheres[id];        // the hit object Vec x=r.o+r.d*t, n=(x-obj.p).norm(), nl=n.dot(r.d)<0?n:n*-1, f=obj.c; double p = f.x>f.y && f.x>f.z ? f.x : f.y>f.z ? f.y : f.z; // max refl if (++depth>5) if (erand48(Xi)<p) f=f*(1/p); else return obj.e; //R.R. if (depth > 100) return Vec();if (obj.refl == DIFF){                  // Ideal DIFFUSE reflection double r1=2*M_PI*erand48(Xi), r2=erand48(Xi), r2s=sqrt(r2); Vec w=nl, u=((fabs(w.x)>.1?Vec(0,1):Vec(1))%w).norm(), v=w%u; Vec d = (u*cos(r1)*r2s + v*sin(r1)*r2s + w*sqrt(1-r2)).norm(); return obj.e + f.mult(radiance(Ray(x,d),depth,Xi)); } else if (obj.refl == SPEC)            // Ideal SPECULAR reflection return obj.e + f.mult(radiance(Ray(x,r.d-n*2*n.dot(r.d)),depth,Xi)); Ray reflRay(x, r.d-n*2*n.dot(r.d));     // Ideal dielectric REFRACTION bool into = n.dot(nl)>0;                // Ray from outside going in? double nc=1, nt=1.5, nnt=into?nc/nt:nt/nc, ddn=r.d.dot(nl), cos2t; if ((cos2t=1-nnt*nnt*(1-ddn*ddn))<0)    // Total internal reflection return obj.e + f.mult(radiance(reflRay,depth,Xi)); Vec tdir = (r.d*nnt - n*((into?1:-1)*(ddn*nnt+sqrt(cos2t)))).norm(); double a=nt-nc, b=nt+nc, R0=a*a/(b*b), c = 1-(into?-ddn:tdir.dot(n)); double Re=R0+(1-R0)*c*c*c*c*c,Tr=1-Re,P=.25+.5*Re,RP=Re/P,TP=Tr/(1-P); return obj.e + f.mult(depth>2 ? (erand48(Xi)<P ?   // Russian roulette radiance(reflRay,depth,Xi)*RP:radiance(Ray(x,tdir),depth,Xi)*TP) : radiance(reflRay,depth,Xi)*Re+radiance(Ray(x,tdir),depth,Xi)*Tr);
} //camera位置(50,52,295.6),往z轴负方向看
int main(int argc, char *argv[]){ int w=1024, h=768, samps=50; // # samples采样 Ray cam(Vec(50,52,295.6), Vec(0,-0.042612,-1).norm()); // cam pos, dir Vec cx=Vec(w*.5135/h), cy=(cx%cam.d).norm()*.5135, r, *c=new Vec[w*h]; #pragma omp parallel for schedule(dynamic, 1) private(r)       // OpenMP //遍历每个像素点,用随机采样的方式求得要射出的光线的方向dfor (int y=0; y<h; y++){                       // Loop over image rows fprintf(stderr,"\rRendering (%d spp) %5.2f%%",samps*4,100.*y/(h-1)); for (unsigned short x=0, Xi[3]={0,0,y*y*y}; x<w; x++)   // Loop cols for (int sy=0, i=(h-y-1)*w+x; sy<2; sy++)     // 2x2 subpixel rows for (int sx=0; sx<2; sx++, r=Vec()){        // 2x2 subpixel cols for (int s=0; s<samps; s++){ double r1=2*erand48(Xi), dx=r1<1 ? sqrt(r1)-1: 1-sqrt(2-r1); double r2=2*erand48(Xi), dy=r2<1 ? sqrt(r2)-1: 1-sqrt(2-r2); Vec d = cx*( ( (sx+.5 + dx)/2 + x)/w - .5) + cy*( ( (sy+.5 + dy)/2 + y)/h - .5) + cam.d; r = r + radiance(Ray(cam.o+d*140,d.norm()),0,Xi)*(1./samps); } // Camera rays are pushed ^^^^^ forward to start in interior c[i] = c[i] + Vec(clamp(r.x),clamp(r.y),clamp(r.z))*.25; }  } FILE *f = fopen("image.ppm", "w");         // Write image to PPM file. fprintf(f, "P3\n%d %d\n%d\n", w, h, 255); for (int i=0; i<w*h; i++) fprintf(f,"%d %d %d ", toInt(c[i].x), toInt(c[i].y), toInt(c[i].z)); } 

4.实验结果图

这是main函数中samps值设定为100时得到的图片,samps值越大清晰度越高,同时运行时间也随之增加,可自行设置samps的值进行测试。

在场景中添加一个塑料球

5.其他场景设计

从左到右从上到下依次为forest——vista——sky——wada

代码:

下面个各个场景的代码实现,可自行将下述某个场景的代码带入上述算法,实现场景验证。

======================================================================
sky
======================================================================
// Idea stolen from Picogen http://picogen.org/ by phresnel/greenhybrid
Vec Cen(50,40.8,-860);
Sphere spheres[] = {//Scene: radius, position, emission, color, material// center 50 40.8 62// floor 0// back  0Sphere(1600, Vec(1,0,2)*3000, Vec(1,.9,.8)*1.2e1*1.56*2,Vec(), DIFF), // sunSphere(1560, Vec(1,0,2)*3500,Vec(1,.5,.05)*4.8e1*1.56*2, Vec(),  DIFF), // horizon sun2
//   Sphere(10000,Cen+Vec(0,0,-200), Vec(0.0627, 0.188, 0.569)*6e-2*8, Vec(.7,.7,1)*.25,  DIFF), // skySphere(10000,Cen+Vec(0,0,-200), Vec(0.00063842, 0.02001478, 0.28923243)*6e-2*8, Vec(.7,.7,1)*.25,  DIFF), // skySphere(100000, Vec(50, -100000, 0),  Vec(),Vec(.3,.3,.3),DIFF), // grndSphere(110000, Vec(50, -110048.5, 0),  Vec(.9,.5,.05)*4,Vec(),DIFF),// horizon brightenerSphere(4e4, Vec(50, -4e4-30, -3000),  Vec(),Vec(.2,.2,.2),DIFF),// mountains
//  Sphere(3.99e4, Vec(50, -3.99e4+20.045, -3000),  Vec(),Vec(.7,.7,.7),DIFF),// mountains snowSphere(26.5,Vec(22,26.5,42),   Vec(),Vec(1,1,1)*.596, SPEC), // white MirrSphere(13,Vec(75,13,82),   Vec(),Vec(.96,.96,.96)*.96, REFR),// GlasSphere(22,Vec(87,22,24),   Vec(),Vec(.6,.6,.6)*.696, REFR)    // Glas2
};======================================================================
nightsky
======================================================================
Sphere spheres[] = {//Scene: radius, position, emission, color, material// center 50 40.8 62// floor 0// back  0//     rad       pos                   emis           col     refl
//  Sphere(1e3,   Vec(1,1,-2)*1e4,    Vec(1,1,1)*5e2,     Vec(), DIFF), // moon
//  Sphere(3e2,   Vec(.6,.2,-2)*1e4,    Vec(1,1,1)*5e3,     Vec(), DIFF), //
//  moonSphere(2.5e3,   Vec(.82,.92,-2)*1e4,    Vec(1,1,1)*.8e2,     Vec(), DIFF), // moon//  Sphere(2.5e4, Vec(50, 0, 0),     Vec(1,1,1)*1e-3,    Vec(.2,.2,1)*0.0075, DIFF), // sky
//  Sphere(2.5e4, Vec(50, 0, 0),  Vec(0.114, 0.133, 0.212)*1e-2,  Vec(.216,.384,1)*0.0007, DIFF), // skySphere(2.5e4, Vec(50, 0, 0),  Vec(0.114, 0.133, 0.212)*1e-2,  Vec(.216,.384,1)*0.003, DIFF), // skySphere(5e0,   Vec(-.2,0.16,-1)*1e4, Vec(1.00, 0.843, 0.698)*1e2,   Vec(), DIFF),  // starSphere(5e0,   Vec(0,  0.18,-1)*1e4, Vec(1.00, 0.851, 0.710)*1e2,  Vec(), DIFF),  // starSphere(5e0,   Vec(.3, 0.15,-1)*1e4, Vec(0.671, 0.780, 1.00)*1e2,   Vec(), DIFF),  // starSphere(3.5e4,   Vec(600,-3.5e4+1, 300), Vec(),   Vec(.6,.8,1)*.01,  REFR),   //poolSphere(5e4,   Vec(-500,-5e4+0, 0),   Vec(),      Vec(1,1,1)*.35,  DIFF),    //hillSphere(16.5,  Vec(27,0,47),         Vec(),              Vec(1,1,1)*.33, DIFF), //hutSphere(7,     Vec(27+8*sqrt(2),0,47+8*sqrt(2)),Vec(),  Vec(1,1,1)*.33,  DIFF), //doorSphere(500,   Vec(-1e3,-300,-3e3), Vec(),  Vec(1,1,1)*.351,    DIFF),  //mntSphere(830,   Vec(0,   -500,-3e3), Vec(),  Vec(1,1,1)*.354,    DIFF),  //mntSphere(490,  Vec(1e3,  -300,-3e3), Vec(),  Vec(1,1,1)*.352,    DIFF),  //mnt
};======================================================================
island
======================================================================
// Inspired by cover of "Time Planet Earth: An Illustrated History"
Vec Cen(50,-20,-860);
Sphere spheres[] = {//Scene: radius, position, emission, color, material// center 50 40.8 62// floor 0// back  0//     rad       pos                   emis           col     reflSphere(160,  Cen+Vec(0, 600, -500),Vec(1,1,1)*2e2, Vec(),  DIFF), // sunSphere(800, Cen+Vec(0,-880,-9120),Vec(1,1,1)*2e1, Vec(),  DIFF), // horizonSphere(10000,Cen+Vec(0,0,-200), Vec(0.0627, 0.188, 0.569)*1e0, Vec(1,1,1)*.4,  DIFF), // sky//  Sphere(1000, Cen+Vec(0,-1080,-8020),Vec(1,1,1)*2e1, Vec(),  DIFF), // horizon
//  Sphere(10000,Cen+Vec(0,0,-200), Vec(0.0627, 0.188, 0.569)*1e0, Vec(1,1,1)*.3,  DIFF), // sky//  Sphere(800, Cen+Vec(0,-720,-200),Vec(),  Vec(0, 0.588, 0.8),  REFR), // water
//  Sphere(800, Cen+Vec(0,-720,-200),Vec(),  Vec(0.106, 0.725, 0.949),  REFR), // water
//  Sphere(800, Cen+Vec(0,-720,-200),Vec(),  Vec(0.110, 0.988, 0.945),  REFR), // waterSphere(800, Cen+Vec(0,-720,-200),Vec(),  Vec(0.110, 0.898, 1.00)*.996,  REFR), // waterSphere(790, Cen+Vec(0,-720,-200),Vec(),  Vec(.4,.3,.04)*.6,    DIFF), // earthSphere(325, Cen+Vec(0,-255,-50), Vec(),  Vec(.4,.3,.04)*.8,       DIFF), // islandSphere(275, Cen+Vec(0,-205,-33), Vec(),  Vec(.02,.3,.02)*.75,      DIFF), // grass
};======================================================================
vista
======================================================================
Vec Cen(50,-20,-860);
Sphere spheres[] = {//Scene: radius, position, emission, color, material// center 50 40.8 62// floor 0// back  0//     rad       pos                   emis           col     reflSphere(8000, Cen+Vec(0,-8000,-900),Vec(1,.4,.1)*5e-1, Vec(),  DIFF), // sunSphere(1e4,  Cen+Vec(), Vec(0.631, 0.753, 1.00)*3e-1, Vec(1,1,1)*.5,  DIFF), // skySphere(150,  Cen+Vec(-350,0, -100),Vec(),  Vec(1,1,1)*.3,  DIFF), // mntSphere(200,  Cen+Vec(-210,0,-100), Vec(),  Vec(1,1,1)*.3,  DIFF), // mntSphere(145,  Cen+Vec(-210,85,-100),Vec(),  Vec(1,1,1)*.8,  DIFF), // snowSphere(150,  Cen+Vec(-50,0,-100),  Vec(),  Vec(1,1,1)*.3,  DIFF), // mntSphere(150,  Cen+Vec(100,0,-100),  Vec(),  Vec(1,1,1)*.3,  DIFF), // mntSphere(125,  Cen+Vec(250,0,-100),  Vec(),  Vec(1,1,1)*.3,  DIFF), // mntSphere(150,  Cen+Vec(375,0,-100),  Vec(),  Vec(1,1,1)*.3,  DIFF), // mntSphere(2500, Cen+Vec(0,-2400,-500),Vec(),  Vec(1,1,1)*.1,  DIFF), // mnt baseSphere(8000, Cen+Vec(0,-8000,200), Vec(),  Vec(.2,.2,1),    REFR), // waterSphere(8000, Cen+Vec(0,-8000,1100),Vec(),  Vec(0,.3,0),     DIFF), // grassSphere(8   , Cen+Vec(-75, -5, 850),Vec(),  Vec(0,.3,0),     DIFF), // bushSphere(30,   Cen+Vec(0,   23, 825),Vec(),  Vec(1,1,1)*.996, REFR), // ballSphere(30,  Cen+Vec(200,280,-400),  Vec(),  Vec(1,1,1)*.8,  DIFF),   // cloudsSphere(37,  Cen+Vec(237,280,-400),  Vec(),  Vec(1,1,1)*.8,  DIFF),   // cloudsSphere(28,  Cen+Vec(267,280,-400),  Vec(),  Vec(1,1,1)*.8,  DIFF),   // cloudsSphere(40,  Cen+Vec(150,280,-1000),  Vec(),  Vec(1,1,1)*.8,  DIFF),  // cloudsSphere(37,  Cen+Vec(187,280,-1000),  Vec(),  Vec(1,1,1)*.8,  DIFF),  // cloudsSphere(40,  Cen+Vec(600,280,-1100),  Vec(),  Vec(1,1,1)*.8,  DIFF),  // cloudsSphere(37,  Cen+Vec(637,280,-1100),  Vec(),  Vec(1,1,1)*.8,  DIFF),  // cloudsSphere(37,  Cen+Vec(-800,280,-1400),  Vec(),  Vec(1,1,1)*.8,  DIFF), // cloudsSphere(37,  Cen+Vec(0,280,-1600),  Vec(),  Vec(1,1,1)*.8,  DIFF),    // cloudsSphere(37,  Cen+Vec(537,280,-1800),  Vec(),  Vec(1,1,1)*.8,  DIFF),  // clouds};======================================================================
overlap
======================================================================
double D=50;
double R=40;
Sphere spheres[N];// = {//Scene: radius, position, emission, color, materialSphere(150, Vec(50+75,28,62), Vec(1,1,1)*0e-3, Vec(1,.9,.8)*.93, REFR),Sphere(28,  Vec(50+5,-28,62), Vec(1,1,1)*1e1, Vec(1,1,1)*0, DIFF),Sphere(300, Vec(50,28,62), Vec(1,1,1)*0e-3, Vec(1,1,1)*.93, SPEC)
};======================================================================
wada
======================================================================
double R=60;
//double R=120;
double T=30*M_PI/180.;
double D=R/cos(T);
double Z=60;
Sphere spheres[] = {//Scene: radius, position, emission, color, material// center 50 40.8 62// floor 0// back  0Sphere(1e5, Vec(50, 100, 0),      Vec(1,1,1)*3e0, Vec(), DIFF), // skySphere(1e5, Vec(50, -1e5-D-R, 0), Vec(),     Vec(.1,.1,.1),DIFF),           //grndSphere(R, Vec(50,40.8,62)+Vec( cos(T),sin(T),0)*D, Vec(), Vec(1,.3,.3)*.999, SPEC), //redSphere(R, Vec(50,40.8,62)+Vec(-cos(T),sin(T),0)*D, Vec(), Vec(.3,1,.3)*.999, SPEC), //grnSphere(R, Vec(50,40.8,62)+Vec(0,-1,0)*D,         Vec(), Vec(.3,.3,1)*.999, SPEC), //blueSphere(R, Vec(50,40.8,62)+Vec(0,0,-1)*D,       Vec(), Vec(.53,.53,.53)*.999, SPEC), //backSphere(R, Vec(50,40.8,62)+Vec(0,0,1)*D,      Vec(), Vec(1,1,1)*.999, REFR), //front//   Sphere(R, Vec(50,35,Z)+Vec( cos(T),sin(T),0)*D, Vec(1,1,1)*1e-1, Vec(1,1,1)*.999, SPEC), //red
//   Sphere(R, Vec(50,35,Z)+Vec(-cos(T),sin(T),0)*D, Vec(1,1,1)*1e-1, Vec(1,1,1)*.999, SPEC), //grn
//   Sphere(R, Vec(50,35,Z)+Vec(0,-1,0)*D,           Vec(1,1,1)*1e-1, Vec(1,1,1)*.999, SPEC), //blue
//   Sphere(R, Vec(50,35,Z)+Vec(0,0,-1)*D*1.6,       Vec(1,1,1)*0e-1, Vec(0.275, 0.612, 0.949)*.999, SPEC), //back
//  Sphere(R, Vec(50,40.8,62)+Vec(0,0,1)*D*.2877,          Vec(1,1,1)*0e-1, Vec(1,1,1)*.999, REFR), //front};======================================================================
wada2
======================================================================
//double R=60;
double R=120;     // radius
double T=30*M_PI/180.;
double D=R/cos(T);     //distance
// double D=60;     //distance
// double R=D*sqrt(2);
double Z=62;
Vec C=Vec(0.275, 0.612, 0.949);
Sphere spheres[] = {//Scene: radius, position, emission, color, materialSphere(R, Vec(50,28,Z)+Vec( cos(T),sin(T),0)*D,    C*6e-2,Vec(1,1,1)*.996, SPEC), //redSphere(R, Vec(50,28,Z)+Vec(-cos(T),sin(T),0)*D,    C*6e-2,Vec(1,1,1)*.996, SPEC), //grnSphere(R, Vec(50,28,Z)+Vec(0,-1,0)*D,              C*6e-2,Vec(1,1,1)*.996, SPEC), //blueSphere(R, Vec(50,28,Z)+Vec(0,0,-1)*R*2*sqrt(2./3.),C*0e-2,Vec(1,1,1)*.996, SPEC), //back
//  Sphere(1e5, Vec(50,28,Z)+Vec(0,0,1e5+170),   Vec(1,1,1)*0,Vec(1,1,1)*.996, SPEC), //front
//  Sphere(2*R*2*sqrt(2./3.)-R*2*sqrt(2./3.)/3., Vec(50,28,Z)+Vec(0,0,-R*2*sqrt(2./3.)/3.),   Vec(1,1,1)*0,Vec(1,1,1)*.3333, SPEC), //frontSphere(2*2*R*2*sqrt(2./3.)-R*2*sqrt(2./3.)/3., Vec(50,28,Z)+Vec(0,0,-R*2*sqrt(2./3.)/3.),   Vec(1,1,1)*0,Vec(1,1,1)*.5, SPEC), //front
};======================================================================
forest
======================================================================
Vec tc(0.0588, 0.361, 0.0941);
Vec sc = Vec(1,1,1)*.7;
Sphere spheres[] = {//Scene: radius, position, emission, color, material// center 50 40.8 62// floor 0// back  0
//  Sphere(1e5, Vec(50, 1e5+100, 0),  Vec(1,1,1)*1,Vec(),DIFF), //lite
//  Sphere(1e5, Vec(50, -1e5, 0),  Vec(),Vec(.3,.3,.1),DIFF), //grnd
//  Sphere(1e5, Vec(50, 1e5+100, 0),  Vec(0.761, 0.875, 1.00)*1.3,Vec(),DIFF),
//  //liteSphere(1e5, Vec(50, 1e5+130, 0),  Vec(1,1,1)*1.3,Vec(),DIFF), //liteSphere(1e2, Vec(50, -1e2+2, 47),  Vec(),Vec(1,1,1)*.7,DIFF), //grndSphere(1e4, Vec(50, -30, 300)+Vec(-sin(50*M_PI/180),0,cos(50*M_PI/180))*1e4, Vec(), Vec(1,1,1)*.99,SPEC),// mirr LSphere(1e4, Vec(50, -30, 300)+Vec(sin(50*M_PI/180),0,cos(50*M_PI/180))*1e4,  Vec(), Vec(1,1,1)*.99,SPEC),// mirr RSphere(1e4, Vec(50, -30, -50)+Vec(-sin(30*M_PI/180),0,-cos(30*M_PI/180))*1e4,Vec(), Vec(1,1,1)*.99,SPEC),// mirr FLSphere(1e4, Vec(50, -30, -50)+Vec(sin(30*M_PI/180),0,-cos(30*M_PI/180))*1e4, Vec(), Vec(1,1,1)*.99,SPEC),// mirrSphere(4, Vec(50,6*.6,47),   Vec(),Vec(.13,.066,.033), DIFF),//"tree"Sphere(16,Vec(50,6*2+16*.6,47),   Vec(), tc,  DIFF),//"tree"Sphere(11,Vec(50,6*2+16*.6*2+11*.6,47),   Vec(), tc,  DIFF),//"tree"Sphere(7, Vec(50,6*2+16*.6*2+11*.6*2+7*.6,47),   Vec(), tc,  DIFF),//"tree"Sphere(15.5,Vec(50,1.8+6*2+16*.6,47),   Vec(), sc,  DIFF),//"tree"Sphere(10.5,Vec(50,1.8+6*2+16*.6*2+11*.6,47),   Vec(), sc,  DIFF),//"tree"Sphere(6.5, Vec(50,1.8+6*2+16*.6*2+11*.6*2+7*.6,47),   Vec(), sc,  DIFF),//"tree"
};

数据可视化1—蒙特卡罗光线追踪相关推荐

  1. python数据动态可视化进阶版,Matplotlib Animations 数据可视化进阶

    原标题:Matplotlib Animations 数据可视化进阶 如果你对我的代码有兴趣,可以在我的GitHub查看.当你第一次执行时,代码会报错(我一直没有解决),但是同样的代码框再执行一次,就能 ...

  2. 【置顶】利用 NLP 技术做简单数据可视化分析教程(实战)

    置顶 本人决定将过去一段时间在公司以及日常生活中关于自然语言处理的相关技术积累,将在gitbook做一个简单分享,内容应该会很丰富,希望对你有所帮助,欢迎大家支持. 内容介绍如下 你是否曾经在租房时因 ...

  3. 只要5分钟用数据可视化带你看遍11月份新闻热点事件

    2017年11月份已经离我们而去,在过去的11月份我们也许经历了双十一的剁手,也可能亲眼看见了别人剁手.11月份的北京大兴区发生了"11·18"重大火灾,国内多家幼儿园也多次上了头 ...

  4. 机器学习PAL数据可视化

    机器学习PAL数据可视化 本文以统计全表信息为例,介绍如何进行数据可视化. 前提条件 完成数据预处理,详情请参见数据预处理. 操作步骤 登录PAI控制台. 在左侧导航栏,选择模型开发和训练 > ...

  5. 2021年大数据ELK(二十七):数据可视化(Visualize)

    全网最详细的大数据ELK文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 数据可视化(Visualize) 一.数据可视化的类型 二.以饼图展示404与 ...

  6. legend位置 pyecharts_实验|pyecharts数据可视化分析-1

    1. 实验介绍 本实验主要介绍pyecharts基本特点与属性. 1.1. 实验目的 了解pyecharts功能.特点.与安装方式. 1.2. 知识点 pyecharts特点 pyecharts图表 ...

  7. matlab数据可视化总结,机器学习----Matlab数据可视化总结(plot篇)

    前言 通过资料的整理,使用Matlab语言的plot函数将数据可视化,plota函数也是一个比较常用的二维绘图函数,针对向量或矩阵.如果你也想试一试,初学者记得使用clf.close或close al ...

  8. graphpad做折线图坐标轴数字_pandas做数据可视化具体操作,快来看看吧

    常见的数据可视化库有: matplotlib 是最常见的2维库,可以算作可视化的必备技能库,由于matplotlib是比较底层的库,api很多,代码学起来不太容易. seaborn 是建构于matpl ...

  9. GitHub开源城市结构公交路线数据可视化

    本开源项目用公交路线数据,还原城市结构,通过数据可视化手段,还原了 30 多个城市的城市结构. 该项目中有数据获取和处理的脚本,而且该项目充分体现了数据可视化带来的便利和效果,易于激发学习编程的热情. ...

  10. 【seaborn】(1) 数据可视化,绘图风格、布局

    各位同学好,今天和大家分享一下如何使用 seaborn 库进行数据可视化.在 matplotlib 的基础上进一步美化绘图.主要内容有:默认风格 sns.set(), 主题风格 sns.set_sty ...

最新文章

  1. 洛谷1042 乒乓球 解题报告
  2. java利用求余水仙花数_java求水仙花数
  3. OSSIM中配置网络资产监控
  4. Maven指令的生命周期
  5. c语言读取acc文件的采样率,C语言文件操作:打开检查文件指针访问模式
  6. python测试框架数据生成工具最全资源汇总
  7. ant 路径_在Ant中显示路径
  8. 学术工业界大佬联合打造:ML产品落地流程指南
  9. excel插入行 uipath_Uipath中excel的activities用法介绍
  10. 【视频教程】捷微开发视频系统讲课-陆续更新
  11. CV Code | 计算机视觉开源周报 20190701期
  12. CCF201709试题
  13. 华为崔景龙:FNV是下一代MBB网络演进的技术驱动
  14. 缺少计算机所需的介质程序,UEFI安装Win8提示缺少所需的介质驱动程序怎么办?...
  15. Metricbeat监听容器CPU利用率,内存等使用情况,发送给ElasticSearch并展示在kibana
  16. 删除文件夹遇到的 错误ox80070091:目录不是空的错误解决
  17. 迷你csgo饰品租赁系统
  18. OpenCV之findContours获取轮廓(Python版)
  19. 为什么沃尔玛等零售商会结成移动支付联盟 ?
  20. Excel 绘制多数据散点图

热门文章

  1. mac上安装linux双系统,怎么在台式一体机上安装双系统?
  2. 使用xpath批量爬取堆糖图片
  3. 如何将flac音频格式转换mp3格式呢
  4. MFC快速创建bmp图片
  5. 识别“百度权重”作弊的方法
  6. 【面经】数据开发一面-美团暑期实习
  7. 从单体式架构迁移到微服务架构
  8. 介绍几个免费的英文ASP.NET的CMS程序
  9. ASP.NET制作调查问卷
  10. 我的VSTO之路(二):VSTO程序基本知识