Ejemplo n.º 1
0
glm::vec3 indirect(const glm::vec3 &c, const glm::vec3 &p, const glm::vec3 &n, const Glass &glass, int iterations)
{
    float ior = 1.5f;

    // Calcul du rayon réfléchi
    glm::vec3 direction = reflect(c,n);
    glm::vec3 directionNorm = glm::normalize(direction);
    Ray rayReflexion{p+directionNorm*0.1f, directionNorm};

    // Calcul du rayon réfracté
    glm::vec3 vecRefract;
    refract(-c, n, ior, vecRefract);
    Ray rayRefraction{p+vecRefract*0.1f, vecRefract};

    // Calcul du coefficient reflechi/refracte

    float coeff = fresnelR(-c, n, ior);

    float rand = random_u();

    if (rand < coeff)
    {
        return radiance(rayReflexion, iterations-1);
    }
    return radiance(rayRefraction, iterations-1) * glass.color;

    //return radiance(rayReflexion, iterations-1) * coeff + radiance(rayRefraction, iterations-1) * (1- coeff);
}
Ejemplo n.º 2
0
glm::vec3 indirect(const glm::vec3 &c, const glm::vec3 &p, const glm::vec3 &n, const Diffuse &diffuse, int iterations)
{
    float pdf;
    glm::vec3 directionRay = sample_sphere(1, random_u(), random_u(), pdf, n);
    Ray ray{p+directionRay*0.1f, directionRay};
    return radiance(ray, iterations-1) * diffuse.color;
}
Ejemplo n.º 3
0
static cv::Mat generateRadianceMap(const cv::Mat& rc)
{
  cv::Size size = getImage(0).size();
  
  cv::Mat_<cv::Vec3f> radiance(size);
  
  for (int y = 0; y < size.height; ++y) {
    for (int x = 0; x < size.width; ++x) {
      cv::Vec3f sum(0,0,0), wsum(0,0,0);
      
      for (int p = 0, n = numImages(); p < n; ++p) {
        const cv::Mat& img = getImage(p);
        cv::Vec3b c = img.at<cv::Vec3b>(y, x);
        float exptime = getExposureTime(p);
        
        cv::Vec3f tmp, wtmp(weight(c[0]), weight(c[1]), weight(c[2]));
        tmp[0] = (rc.at<float>(c[0], 0) - std::log(exptime)) * wtmp[0];
        tmp[1] = (rc.at<float>(c[1], 1) - std::log(exptime)) * wtmp[1];
        tmp[2] = (rc.at<float>(c[2], 2) - std::log(exptime)) * wtmp[2];
        sum += tmp;
        wsum += wtmp;
      }
      
      cv::Vec3f tmp;
      tmp[0] = std::exp( sum[0] / wsum[0] );
      tmp[1] = std::exp( sum[1] / wsum[1] );
      tmp[2] = std::exp( sum[2] / wsum[2] );
      
      radiance.at<cv::Vec3f>(y, x) = tmp;
    }
  }
  
  return radiance;
}
Ejemplo n.º 4
0
glm::vec3 indirect(const glm::vec3 &c, const glm::vec3 &p, const glm::vec3 &n, const Mirror &mirror, int iterations)
{
    glm::vec3 direction = reflect(c,n);
    glm::vec3 directionNorm = glm::normalize(direction);
    Ray r{p+directionNorm*0.1f, directionNorm};
    return radiance(r, iterations-1) * mirror.color;
}
Ejemplo n.º 5
0
int main(int argc, char *argv[]){
  int w=1024, h=768, samps = argc==2 ? atoi(argv[1])/4 : 1; // # 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
  for (int y=0; y<h; y++){                       // Loop over image rows
    // *** Commented out for Visual Studio, fprintf is not thread-safe
    //fprintf(stderr,"\rRendering (%d spp) %5.2f%%",samps*4,100.*y/(h-1));
    unsigned short Xi[3]={0,0,y*y*y}; // *** Moved outside for VS2012
    for (unsigned short x=0; 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));
}
Ejemplo n.º 6
0
//-------------------------------------------------------------------------------
// @ Player::Player()
//-------------------------------------------------------------------------------
// Constructor
//-------------------------------------------------------------------------------
Player::Player()
{
    mRadius = 5.0f;

    mSphereIndices = nullptr;

    mSphereVerts = nullptr;

    mShader = IvRenderer::mRenderer->GetResourceManager()->CreateShaderProgram(
        IvRenderer::mRenderer->GetResourceManager()->CreateVertexShaderFromFile(
        "directionalShader"),
        IvRenderer::mRenderer->GetResourceManager()->CreateFragmentShaderFromFile(
        "directionalShader"));

    IvRenderer::mRenderer->SetShaderProgram(mShader);

    IvVector3 radiance(1.0f, 1.0f, 1.0f);
    mShader->GetUniform("dirLightRadiance")->SetValue(radiance, 0);

    mRotate.Identity();

    mLightDir = IvVector3(1.0f, 0.0f, 0.0f);

    CreateSphere();
}   // End of Player::Player()
Ejemplo n.º 7
0
glm::vec3 indirect(const Ray &rOrigine, const Ray &rReflect, const glm::vec3 &p, const glm::vec3 & n, int countdown, const Diffuse &diffuse) {
    float pdf;
    glm::vec3 w = glm::normalize(sample_sphere(1, random_u(), random_u(), pdf, n));
    Ray rIndirect{p+0.1f*w, w};
    return radiance(rIndirect, countdown);
    //return glm::vec3(0,0,0);
}
Ejemplo n.º 8
0
void Renderer::render() const
{
	Ray		ray;
	P2d		pp;

	Random rnd(3141592);

	C3f *image = new C3f[ _vp.width * _vp.height];
	double invNumSample = 1.0 / _vp.numSamples;

	// OpenMP
	#pragma omp parallel for schedule(dynamic, 1) num_threads(4)
	for (int y = 0; y < _vp.height; y++)
	{
		std::cerr << "Rendering (y = " << y << ") " << (100.0 * y / (_vp.height - 1)) << "%" << std::endl;
		for (int x = 0; x < _vp.width; x++)
		{
			const int imageIndex = (_vp.height - y - 1) * _vp.width + x;
			C3f pixelColor(0.0f, 0.0f, 0.0f);
			for (int j = 0; j < _vp.numSamples; j++)
			{
				pp.x = _vp.s*(- x + 0.5 * _vp.width);
				pp.y = _vp.s*(y - 0.5 * _vp.height);
				ray = _camera->getRay(pp);
				pixelColor = pixelColor + radiance(ray, &rnd, 0) / _vp.numSamples;
			}
			image[imageIndex] = C3f(pixelColor);
		}
	}

	savePPM("output.ppm", image, _vp.width, _vp.height);
	delete[] image;
}
Ejemplo n.º 9
0
Vec3 DiffuseMaterial::out_direction(Vec3 const &in, Vec3 const &norm, double &brdf, RGB &color, CRandomMersenne *rng)
{
	// Generamos una nueva direccion. Sera una direccion aleatoria en la
	// semiesfera definida por la normal.
	brdf    = 1.0f;
	color   = radiance() * brdf;
	return versor(random_dir(norm, rng->Random(), rng->Random()));
}
Ejemplo n.º 10
0
glm::vec3 indirect(const Ray &rOrigine, const Ray &rReflect, const glm::vec3 &p,  const glm::vec3 & n, int countdown, const Glass &glass) {

    float fresnel = fresnelR(-rOrigine.direction,n, 1.5);
    glm::vec3 refracted;
    bool canRefract = refract(-rOrigine.direction, n, 1.5, refracted);
    Ray rRefracted{p+refracted*0.1f, refracted};
    if(canRefract) {
        float u = random_u();
        if(u < fresnel)
            return radiance(rReflect, countdown);
        else
            return radiance(rRefracted, countdown);
    }
        //return fresnel*radiance(rReflect, countdown)+(1-fresnel)*radiance(rRefracted, countdown);
    else
        return fresnel*radiance(rReflect, countdown);
}
Ejemplo n.º 11
0
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 > 255) return obj.e;
	if(++depth > 5) if(erand48(Xi) < p) f = f*(1 / p); else return obj.e; //R.R.
	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);
}
Ejemplo n.º 12
0
void tracer::Pathtracer::trace(const Ray& ray) {
	// random number generation
	std::random_device rd;
	std::mt19937 engine(rd());
	const bool debug = true;
	const bool considerEmission = true;
	glm::vec3 rad = radiance(ray, engine, 0, considerEmission, debug);
	std::cout << "returned radiance: " << rad << std::endl;
}
int main(int argc, char **argv) {
	int width = 640;
	int height = 480;
	int photon_num = 50000;
	double gather_photon_radius = 32.0;
	int gahter_max_photon_num = 64;
	int final_gather = 64; // final_gather個のサンプル
	int direct_light_samples = 64;

	// カメラ位置
	Ray camera(Vec(50.0, 52.0, 295.6), Normalize(Vec(0.0, -0.042612, -1.0)));
	// シーン内でのスクリーンのx,y方向のベクトル
	Vec cx = Vec(width * 0.5135 / height);
	Vec cy = Normalize(Cross(cx, camera.dir)) * 0.5135;
	Color *image = new Color[width * height];

	// フォトンマップ構築
	PhotonMap photon_map;
	create_photon_map(photon_num, &photon_map);

	// イラディアンスキャッシュ
	// 事前構築(なにかと都合がよい)
	IrradianceCache cache;
	for (int i = 0; i < 10000; i ++) {
		if (i % 1000 == 0)
			std::cout << "*";
		pre_build_irradiance_cache(camera, cx, cy, width, height, &photon_map, &cache, gather_photon_radius, gahter_max_photon_num, final_gather, direct_light_samples);
	}

	for (int y = 0; y < height; y ++) {
		std::cerr << "Rendering " << (100.0 * y / (height - 1)) << "%" << std::endl;
		srand(y * y * y);
		for (int x = 0; x < width; x ++) {
			int image_index = y * width + x;	
			image[image_index] = Color();

			// 2x2のサブピクセルサンプリング
			for (int sy = 0; sy < 2; sy ++) {
				for (int sx = 0; sx < 2; sx ++) {
					// テントフィルターによってサンプリング
					// ピクセル範囲で一様にサンプリングするのではなく、ピクセル中央付近にサンプルがたくさん集まるように偏りを生じさせる
					const double r1 = 2.0 * rand01(), dx = r1 < 1.0 ? sqrt(r1) - 1.0 : 1.0 - sqrt(2.0 - r1);
					const double r2 = 2.0 * rand01(), dy = r2 < 1.0 ? sqrt(r2) - 1.0 : 1.0 - sqrt(2.0 - r2);
					Vec dir = cx * (((sx + 0.5 + dx) / 2.0 + x) / width - 0.5) +
								cy * (((sy + 0.5 + dy) / 2.0 + y) / height- 0.5) + camera.dir;
					image[image_index] = image[image_index] + radiance(Ray(camera.org + dir * 130.0, Normalize(dir)), 0, &photon_map, &cache, gather_photon_radius, gahter_max_photon_num, final_gather, direct_light_samples);
				}
			}
		}
	}

	// .hdrフォーマットで出力
	save_hdr_file(std::string("image.hdr"), image, width, height);
}
Ejemplo n.º 14
0
int render(const Setting& setting, Camera& camera, Screen& screen, Scene& scene, ImageBuffer& buffer)
{
	int time_count = 1;
	clock_t start_time, current_time;
	float now_time;
	start_time = clock();
	char fname[255];

	for (int y = 0; y < setting.reso_h; y++)
	{
		Imath::Rand48 rnd;
		std::cout << "Rendering (y = " << y << ") " << (100.0 * y / (setting.reso_h - 1)) << "%" << std::endl;

		for (int x = 0; x < setting.reso_w; x++)
		{
			int index = (setting.reso_h - y - 1) * setting.reso_w + x;
			buffer[index] = Imath::C3f(0,0,0);
			
			for (int sy = 0; sy < setting.supersamples; sy++)
			{
				for (int sx = 0; sx < setting.supersamples; sx++)
				{
					Imath::C3f acm_rad = Imath::C3f(0,0,0);

					for (int s = 0; s < setting.samples; s++)
					{
						Ray ray = Ray(camera,screen,setting,x,y,sx,sy);
						acm_rad += radiance(scene, ray, rnd, 0) / setting.samples / (setting.supersamples * setting.supersamples);
						buffer[index] += acm_rad;

						current_time = clock();
						now_time = static_cast<float>((current_time - start_time) / CLOCKS_PER_SEC);
						if (now_time > time_count * 60.0f)
						{
							std::cout << "width:" << setting.reso_w << std::endl;
							std::cout << "height:" << setting.reso_h << std::endl;
							std::cout << "sample:" << setting.samples << std::endl;
							std::cout << "subpixel:" << setting.supersamples << std::endl;
							std::cout << time_count << "minute(s)" << std::endl;
							std::cout << "image output..." << std::endl;
							sprintf(fname, "out_%02d.bmp", time_count);
							write_bmp(fname, buffer, setting);
							time_count++;
						}
					}
				}
			}

		}
	}

	return 0;
}
Ejemplo n.º 15
0
inline void compute_inner(int y, int w, int h, int samps, Ray &cam, Vec &cx, Vec &cy, Vec &r, Vec *c) {
	//fprintf(stderr, "\rRendering (%d spp) %5.2f%%", samps * 4, 100.*y / (h - 1));
	for(unsigned short x = 0, Xi[3] = { 0, 0, (unsigned short)(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;
			}
}
void pre_build_irradiance_cache(const Ray &camera, const Vec &cx, const Vec &cy, const int width, const int height,
	PhotonMap *photon_map, IrradianceCache *cache, const double gather_radius, const int gahter_max_photon_num, const int final_gather, const int direct_light_samples) {

	int x = rand01() * width; if (x >= width) x = width - 1;
	int y = rand01() * height; if (y >= height) y = height - 1;
	int sx = rand01() * 2; if (sx >= 2) sx = 1;
	int sy = rand01() * 2; if (sy >= 2) sy = 1;

	// テントフィルターによってサンプリング
	// ピクセル範囲で一様にサンプリングするのではなく、ピクセル中央付近にサンプルがたくさん集まるように偏りを生じさせる
	const double r1 = 2.0 * rand01(), dx = r1 < 1.0 ? sqrt(r1) - 1.0 : 1.0 - sqrt(2.0 - r1);
	const double r2 = 2.0 * rand01(), dy = r2 < 1.0 ? sqrt(r2) - 1.0 : 1.0 - sqrt(2.0 - r2);
	Vec dir = cx * (((sx + 0.5 + dx) / 2.0 + x) / width - 0.5) +
				cy * (((sy + 0.5 + dy) / 2.0 + y) / height- 0.5) + camera.dir;
	radiance(Ray(camera.org + dir * 130.0, Normalize(dir)), 0, photon_map, cache, gather_radius, gahter_max_photon_num, final_gather, direct_light_samples, true);
}
Ejemplo n.º 17
0
C3f Renderer::radiance(const Ray & ray, Random *rnd, const int depth) const
{
	Intersection intersection;
	if (!_scene.intersect(ray, &intersection))
	{
		return C3f(0.0f, 0.0f, 0.0f);
	}

	double prob = intersection.pMaterial->getMaxColor();

	if (depth > 5)
	{
		return C3f(0.0f, 0.0f, 0.0f);
	} else {
		prob = 1.0;
	}
	C3f incomingRadiance(0.0f, 0.0f, 0.0f);
	C3f weight(1.0f, 1.0f, 1.0f);

	V3d w, u, v;
	w = intersection.normal.dot(ray.dir) < 0.0 ? intersection.normal : (-1.0 * intersection.normal);

	if (fabs(w.x) > SR_EPSILON)
	{
		u = (V3d(0.0, 1.0, 0.0).cross(w)).normalized();
	} else {
		u = (V3d(1.0, 0.0, 0.0).cross(w)).normalized();
	}
	v = w.cross(u);
	const double r1 = SR_PITIMES2 * rnd->next01();
	const double r2 = rnd->next01(), r2s = sqrt(r2);

	Ray next;
	next.pos = intersection.position;
	next.dir = (
		u * cos(r1) * r2s +
		v * sin(r1) * r2s +
		w * sqrt(1.0 - r2)).normalized();

	incomingRadiance = radiance(next, rnd, depth + 1);

	weight = intersection.pMaterial->shade() /prob;

	return intersection.pMaterial->getEmission() + weight*incomingRadiance;

}
Ejemplo n.º 18
0
Vec radiance(const Ray &r, int depth, unsigned short *Xi,int E=1){
  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||!p) if (erand48(Xi)<p) f=f*(1/p); else return obj.e*E;
  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();

    // Loop over any lights
    Vec e;
    for (int i=0; i<numSpheres; i++){
      const Sphere &s = spheres[i];
      if (s.e.x<=0 && s.e.y<=0 && s.e.z<=0) continue; // skip non-lights
      
      Vec sw=s.p-x, su=((fabs(sw.x)>.1?Vec(0,1):Vec(1))%sw).norm(), sv=sw%su;
      double cos_a_max = sqrt(1-s.rad*s.rad/(x-s.p).dot(x-s.p));
      double eps1 = erand48(Xi), eps2 = erand48(Xi);
      double cos_a = 1-eps1+eps1*cos_a_max;
      double sin_a = sqrt(1-cos_a*cos_a);
      double phi = 2*M_PI*eps2;
      Vec l = su*cos(phi)*sin_a + sv*sin(phi)*sin_a + sw*cos_a;
      l.norm();
      if (intersect(Ray(x,l), t, id) && id==i){  // shadow ray
        double omega = 2*M_PI*(1-cos_a_max);
        e = e + f.mult(s.e*l.dot(nl)*omega)*M_1_PI;  // 1/pi for brdf
      }
    }
    
    return obj.e*E+e+f.mult(radiance(Ray(x,d),depth,Xi,0));
  } 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);
}
Ejemplo n.º 19
0
Texture::Visualization::Visualization(const Any& a) {
    *this = Visualization();
    if (a.type() == Any::ARRAY) {
        if (a.nameEquals("bumpInAlpha")) {
            *this = bumpInAlpha();
        } else if (a.nameEquals("defaults")) {
            *this = defaults();
        } else if (a.nameEquals("linearRGB")) {
            *this = linearRGB();
        } else if (a.nameEquals("depthBuffer")) {
            *this = depthBuffer();
        } else if (a.nameEquals("packedUnitVector")) {
            *this = packedUnitVector();
        } else if (a.nameEquals("radiance")) {
            *this = radiance();
        } else if (a.nameEquals("reflectivity")) {
            *this = reflectivity();
        } else if (a.nameEquals("sRGB")) {
            *this = sRGB();
        } else if (a.nameEquals("unitVector")) {
            *this = unitVector();
        } else {
            a.verify(false, "Unrecognized Visualization factory method");
        }
    } else {
        a.verifyName("Texture::Visualization", "Visualization");

        AnyTableReader r(a);
        String c;

        if (r.getIfPresent("channels", c)) {
            channels = toChannels(c);
        }

        r.getIfPresent("documentGamma", documentGamma);
        r.getIfPresent("invertIntensity", invertIntensity);
        r.getIfPresent("max", max);
        r.getIfPresent("min", min);
        r.getIfPresent("layer", layer);
        r.getIfPresent("mipLevel", mipLevel);

        r.verifyDone();
    }
}
Ejemplo n.º 20
0
nex::color path_tracer::indirect_illumination(const sampler* sampler, const nex::ray* ray,
        const surface& surface) const
{
        nex::vector wi;
        float pdf = 0.0f;

        nex::color f = surface.bsdf->sample(sampler->get_samples(bsdf_index)[ray->depth],
                                                surface, -ray->direction, &wi, &pdf);

        if ((f == nex::color::black()) || (pdf <= 0.0f)) {
                return nex::color::black();
        }

        nex::ray reflected_ray(surface.position + nex::EPSILON * wi, wi, FLT_MAX, ray->depth + 1);

        bool emittance = (surface.bsdf->get_bxdf(BXDF_SPECULAR) != nullptr);

        float cos = std::abs(nex::dot(surface.normal, wi));

        return radiance(sampler, &reflected_ray, emittance) * f * cos / pdf;
}
Ejemplo n.º 21
0
void tracer::Pathtracer::render(unsigned width, unsigned height) {
	// initialize output texture
	m_output.clear();
	m_output.resize(width * height);
	std::fill(m_output.begin(), m_output.end(), glm::vec4(0.0f));

	// pinhole camera
	Camera& camera = m_scene.getCamera();
	camera.setImagingPlaneResolution(width, height);
	
	// random number generation
	std::random_device rd;
	std::mt19937 engine(rd());
	
	// progress printing
	std::cout.precision(2);
	std::cout.setf(std::ios::fixed, std::ios::floatfield);
	std::string status = "Rendering, done: ";
	float percentage = 0.0f, fraction = 100.0f/height;
	
	// rendering loop
	#pragma omp parallel for schedule(dynamic)
	for (unsigned y = 0; y < height; y++) {
		for (unsigned x = 0; x < width; x++) {
			glm::vec3 outputColor(0.0f);
			for (unsigned s = 0; s < m_samples; s++) {
				Ray ray = camera.castRay(x, y);
				outputColor += radiance(ray, engine) / (float)m_samples;
			}
			m_output[y*width+x] = glm::vec4(color::gammaCompress(glm::clamp(outputColor, 0.0f, 1.0f)), 1.0f);
		}
		#pragma omp critical
		{
		percentage += fraction;
		std::cout << "\r" << status << percentage << "%";
		}
	}
	std::cout << std::endl << std::endl;
}
Ejemplo n.º 22
0
int main(int argc, char *argv[]) {

//  Sphere* S = new Sphere(16.5, Vec(0,0,0), Vec(), Vec(1,1,1)*.999, SPEC);
//  S->intersect(Ray(Vec(50,50,100),Vec(0,0,-1).norm()));
//return 0;

//  int w=1024, h=768, samps = argc==2 ? atoi(argv[1])/4 : 1; // # samples
//  int w=512, h=384, samps = argc==2 ? atoi(argv[1])/4 : 1; // # samples
  int w=256, h=192, samps = argc==2 ? atoi(argv[1])/4 : 1; // # 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;
  Vec *frame=new Vec[w*h];

#pragma omp parallel for schedule(dynamic, 1) private(r)
  for (unsigned short 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,(unsigned short)(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++) {
            float r1=2*erand48(Xi), dx=r1<1 ? sqrt(r1)-1 : 1-sqrt(2-r1);
            float 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
          frame[i] = frame[i] + Vec(clamp(r.x), clamp(r.y), clamp(r.z))*.25;
        }
      }
    }
  }

  // Write image to PPM file.
  FILE *f = fopen("image.ppm", "wb");
  fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
  for (int i=0; i<w*h; i++)
    fprintf(f, "%c%c%c", toInt(frame[i].x), toInt(frame[i].y), toInt(frame[i].z));
}
Ejemplo n.º 23
0
int main (int, char **)
{
    QTime timer;
    timer.start();
    int w = 768, h = 768;
    int samplesLight = 1;
    int samplesAliasing = 1;
    std::vector<glm::vec3> colors(w * h, glm::vec3{0.f, 0.f, 0.f});

    Ray cam {{50, 52, 295.6}, glm::normalize(glm::vec3{0, -0.042612, -1})};	// cam pos, dir
    float near = 1.f;
    float far = 10000.f;

    glm::mat4 camera =
        glm::scale(glm::mat4(1.f), glm::vec3(float(w), float(h), 1.f))
        * glm::translate(glm::mat4(1.f), glm::vec3(0.5, 0.5, 0.f))
        * glm::perspective(float(54.5f * pi / 180.f), float(w) / float(h), near, far)
        * glm::lookAt(cam.origin, cam.origin + cam.direction, glm::vec3(0, 1, 0))
        ;

    glm::mat4 screenToRay = glm::inverse(camera);

    #pragma omp parallel for schedule(dynamic)
    for (int y = 0; y < h; y++)
    {
        std::cerr << "\rRendering: " << 100 * y / (h - 1) << "%";

        for (unsigned short x = 0; x < w; x++)
        {
            glm::vec3 r(0,0,0);

            for (int samplesA = 0; samplesA < samplesAliasing; ++samplesA)
            {
                   float aleaX = random_u()-0.5;
                   float aleaY = random_u()-0.5;

                   glm::vec4 p0 = screenToRay * glm::vec4{float(x + aleaX), float(h - y + aleaY), 0.f, 1.f};
                   glm::vec4 p1 = screenToRay * glm::vec4{float(x + aleaX), float(h - y + aleaY), 1.f, 1.f};

                   glm::vec3 pp0 = glm::vec3(p0 / p0.w);
                   glm::vec3 pp1 = glm::vec3(p1 / p1.w);

                   glm::vec3 d = glm::normalize(pp1 - pp0);

                   for (int samplesL = 0; samplesL < samplesLight; ++samplesL) {
                       r += radiance (Ray{pp0, d});
                   }
            }

            r = r/float(samplesLight*samplesAliasing);

            colors[y * w + x] += glm::clamp(r, glm::vec3(0.f, 0.f, 0.f), glm::vec3(1.f, 1.f, 1.f));// * 0.25f;
        }
    }

    std::cout << "\n" << timer.elapsed()/1000.0 << "s" << std::endl;

    {
        std::fstream f("image.ppm", std::fstream::out);
        f << "P3\n" << w << " " << h << std::endl << "255" << std::endl;

        for (auto c : colors)
            f << toInt(c.x) << " " << toInt(c.y) << " " << toInt(c.z) << " ";
    }

}
Ejemplo n.º 24
0
int main(int argc, char **argv) {
	int width = 640;
	int height = 480;
	int samples = 16;

	// カメラ位置
	Ray camera(Vec(50.0, 52.0, 295.6), Normalize(Vec(0.0, -0.042612, -1.0)));
	// シーン内でのスクリーンのx,y方向のベクトル
	Vec cx = Vec(width * 0.5135 / height);
	Vec cy = Normalize(Cross(cx, camera.dir)) * 0.5135;
	Color *image = new Color[width * height];
	Color *image_interpolated = new Color[width * height];

	// フォームファクター計算
	// 16x16に分割、フォームファクターの計算に(3x3)^2サンプル使ってモンテカルロ積分する
	calc_form_factor(16, 16, 3);

	// ガウス=ザイデル法でラジオシティ方程式解く
	// 32反復
	for (int i = 0; i < 32; i ++) {
		std::cout << i << " ";
		calc_radiosity(i);
	}

//#pragma omp parallel for schedule(dynamic, 1) num_threads(3)
	for (int y = 0; y < height; y ++) {
		std::cerr << "Rendering (" << samples * 4 << " spp) " << (100.0 * y / (height - 1)) << "%" << std::endl;
		srand(y * y * y);
		for (int x = 0; x < width; x ++) {
			int image_index = y * width + x;	
			image[image_index] = Color();
			image_interpolated[image_index] = Color();

			// 2x2のサブピクセルサンプリング
			for (int sy = 0; sy < 2; sy ++) {
				for (int sx = 0; sx < 2; sx ++) {
					Color accumulated_radiance = Color();
					Color accumulated_radiance2 = Color();
					// 一つのサブピクセルあたりsamples回サンプリングする
					for (int s = 0; s < samples; s ++) {
						// テントフィルターによってサンプリング
						// ピクセル範囲で一様にサンプリングするのではなく、ピクセル中央付近にサンプルがたくさん集まるように偏りを生じさせる
						const double r1 = 2.0 * rand01(), dx = r1 < 1.0 ? sqrt(r1) - 1.0 : 1.0 - sqrt(2.0 - r1);
						const double r2 = 2.0 * rand01(), dy = r2 < 1.0 ? sqrt(r2) - 1.0 : 1.0 - sqrt(2.0 - r2);
						Vec dir = cx * (((sx + 0.5 + dx) / 2.0 + x) / width - 0.5) +
								  cy * (((sy + 0.5 + dy) / 2.0 + y) / height- 0.5) + camera.dir;
						accumulated_radiance = accumulated_radiance + 
							radiance(Ray(camera.org + dir * 130.0, Normalize(dir)), 0, false) / samples;
						accumulated_radiance2 = accumulated_radiance2 + 
							radiance(Ray(camera.org + dir * 130.0, Normalize(dir)), 0, true) / samples;
					}
					image[image_index] = image[image_index] + accumulated_radiance;
					image_interpolated[image_index] = image_interpolated[image_index] + accumulated_radiance2;

				}
			}
		}
	}
	
	// .hdrフォーマットで出力
	save_hdr_file(std::string("image.hdr"), image, width, height);
	save_hdr_file(std::string("image_interpolated.hdr"), image_interpolated, width, height);
}
Ejemplo n.º 25
0
nex::color path_tracer::radiance(const sampler* sampler, nex::ray* ray) const
{
        return radiance(sampler, ray, true);
}
Ejemplo n.º 26
0
// =============================================================
// =============================================================
// =============================================================
int main()
{
	printf("Small MCFTLE: Computing...\n");

	// =============================================================
	// initialize
	// =============================================================
	Vec3d eye(1,0.5,2.3), lookAt(1,0.5,0.5), up(0,1,0);		// camera parameters
	double fov = 45.0;
	Camera camera(eye, lookAt, up, fov, screenResolution);	// pinhole camera
	Frame frame(screenResolution);							// stores pixel statistics
	Flow flow;												// vector field
	Timer timer;											// timer to measure runtime

	// =============================================================
	// progressive rendering
	// =============================================================
	for (int it=0; it<maxIterationsPerPixel; ++it)
	{
		timer.tic();	// start runtime measurement

		#ifdef NDEBUG
		#pragma omp parallel for schedule(dynamic,16)
		#endif
		for (int px=0; px<screenResolution.x*screenResolution.y; ++px)
		{
			// select pixel and generate a ray
			Vec2i pxCoord(px%screenResolution.x, px/screenResolution.x);
			Ray viewRay = camera.GenerateRay(pxCoord);

			// intersect ray with domain (entry and exit)
			Vec2d t;
			if (!flow.IntersectRay(viewRay, t))
				continue;

			// free path sampling to find a scattering event
			FreePathResult fprView = FreePathSampling(viewRay, flow);
			
			Vec3d radiance(1,1,1);	// initialize with radiance of the background (white)

			// if we found a scattering event
			if (fprView.d <= fprView.dmax)
			{
				// compute the scattering albedo c
				Vec3d albedo = ScatteringAlbedo(fprView.ftle);

				// compute scattering location x_s and generate shadow ray
				Vec3d x_s = viewRay.Origin + fprView.d * viewRay.Direction;
				Ray shadowRay(x_s, -lightDirection);

				// intersect shadow ray with domain (determine exit)
				if (!flow.IntersectRay(shadowRay, t))
					continue;

				// free path sampling to find a scattering event on the shadow ray
				FreePathResult fprLight = FreePathSampling(shadowRay, flow);

				// if we have scattered, we are in shadow. (actually visibility would be zero now, but for vis purposes we keep a little bit.)
				double visibility = 1;
				if (fprLight.d <= fprLight.dmax)
					visibility = visibility_minimum;

				// phase function
				double phase = 1.0 / (4.0 * M_PI);		// isotropic phase function

				// compute in-scattered radiance
				radiance = albedo * phase * visibility * lightRadiance;
			}
			// add the result to the pixel statistics
			frame.AddPixel(pxCoord, radiance);
		}
		
		timer.toc();	// finish runtime measurement (prints result to console)

		// write intermediate result to file
		frame.ExportPfm("result.pfm");
		frame.ExportBmp("result.bmp", contrast, brightness, gamma_val);
		printf("Iteration: %i / %i\n", it+1, maxIterationsPerPixel);
	}
	printf("\nComplete!\n");
	return 0;
}
Ejemplo n.º 27
0
glm::vec3 tracer::Pathtracer::radiance(const Ray& ray, std::mt19937& engine, unsigned depth, bool considerEmission, bool debug) {
	std::uniform_real_distribution<float> distribution(0.0f, 1.0f);
	float distance, minimumDistance = std::numeric_limits<float>::max();
	Intersection tmp, isect;
	for (auto it = m_scene.begin(); it != m_scene.end(); ++it) {
		if ((*it)->intersect(ray, tmp)) {
			tmp.valid = true;
			if (debug) {
				std::cout << "testing intersection " << tmp.point << ", distance" << glm::distance2(ray.org, tmp.point) << std::endl;
			}
			if ((distance = glm::distance2(ray.org, tmp.point)) < minimumDistance) {
				minimumDistance = distance;
				isect = tmp;
			}
		}
	}
	
	if (isect.valid) {
		if (debug) { std::cout << "found intersection @ " << isect.point << ", normal: " << isect.normal << std::endl; }
		
		// russian roulette
		const material::Material& material = isect.object->getMaterial();
		glm::vec3 objectColor = material.color;
		float p = MAX(objectColor.r, objectColor.g, objectColor.b);
		if (++depth > 5) {
			if (distribution(engine) < p) {
				objectColor = objectColor / p;
			} else {
				if (considerEmission) {
					return material.emission;
				} else {
					return glm::vec3(0.0f);
				}
			}
		}
		
		if (material.type == material::Material::Type_diffuse) {
			if (debug) { std::cout << "shading diffuse material" << std::endl; }
			
			// construct orthonormal system
			float r1 = 2 * M_PI * distribution(engine);
			float r2 = distribution(engine);
			float r2s = sqrt(r2);
			glm::vec3 w = isect.normal;
			glm::vec3 u = glm::normalize( glm::cross( (fabs(w.x) > 0.1f ? ey : ex), w ) );
			glm::vec3 v = glm::normalize( glm::cross(w, u) );
			glm::vec3 d = glm::normalize((float)(cos(r1) * r2s) * u + (float)(sin(r1) * r2s) * v + (float)sqrt(1-r2) * w);
			Ray scatteredRay(isect.point+epsilon*isect.normal, d);
			if (debug) { std::cout << "tracing next ray: " << scatteredRay << std::endl; }
			
			// compose output color
			glm::vec3 color = (considerEmission ? material.emission : glm::vec3(0.0f));
			// add direct lighting contribution
			color += sampleDirectLighting(isect.point, isect.normal, objectColor, engine);
			// add indirect lighting contribution
			color += objectColor * radiance(scatteredRay, engine, depth, false, debug);
			return color;
		} else if (material.type == material::Material::Type_reflective) {
			if (debug) { std::cout << "shading reflective material" << std::endl; }
			
			Ray reflectedRay(isect.point+epsilon*isect.normal, glm::reflect(ray.dir, isect.normal));
			return material.emission + objectColor * radiance(reflectedRay, engine, depth, true, debug); 
		} else {
			error("Unhandled material type detected");
			return m_scene.getBackgroundColor();
		}
	} else {
		if (debug) { std::cout << "found no intersection" << std::endl; }
		return m_scene.getBackgroundColor();
	}
}
Ejemplo n.º 28
0
Colorf Sky::getRadianceAt(float theta, float phi, bool checkerboard) {
	if(checkerboard) {
		const int x = theta / (pi / 5);
		const int y = phi / (pi / 5);

		const int parity = (x ^ y) % 2;
		const float val = parity ? 150 : 100;

		return Colorf(val, val, val);
	}

	if(theta > pi / 2) {
		return Colorf(0, 0, 0);
	}

	// Preetham sky model
	// http://www.cs.utah.edu/~shirley/papers/sunsky/sunsky.pdf
	//
	// Hints for reading the paper:
	// * we don't consider object light scattering
	//   (maybe needed later when considering far-away moutains or such)
	// * when there's no object, L(0) = 0 (universe background)
	// * don't get distracted by approximations for hand-calculation
	//   (it's simpler (and more flexible) to do numerical calc + smart memoization)
	const float view_height = 0;

	const float alpha_haze = 0.8333;  // haze: /km
	const float alpha_mole = 0.1136;  // molecules: /km

	const Eigen::Vector3f view_direction(
		std::sin(theta) * std::cos(phi),
		std::sin(theta) * std::sin(phi),
		std::cos(theta));	

	// Based on Nishita's 1st-order scattering sky model.
	// We ignore point-to-space decay.
	Colorf radiance(0, 0, 0);
	Colorf decay_here_to_view(1, 1, 1);
	for(int i = 0; i < 50; i++) {
		const float distance = i;
		const float height = distance * std::cos(theta) + view_height;

		//
		const float cos_view_sun = view_direction.dot(sun_direction);

		// Calculate scattering
		// Mie scattering's phase function is not well-described anywhere.
		// But it's said to be very sharp. So
		// we use (1+cos^3 theta)^2/4
		// (http://www.wolframalpha.com/input/?i=plot+r%3D%281%2Bcos%5E3+theta%29%5E2%2F4)
		const Colorf scatter =
			particleDensity(alpha_mole, distance, theta) * rayleigh(cos_view_sun) +
			particleDensity(alpha_haze, distance, theta) * mie(cos_view_sun);

		// Note. decay_space_to_here and decay_here_to_view are not colinear.
		radiance += sun_power
			.cwiseProduct(scatter)
			.cwiseProduct(decay_here_to_view);

		const Colorf decay_scatter =
			particleDensity(alpha_mole, distance, theta) * rayleighTotal() +
			particleDensity(alpha_haze, distance, theta) * mieTotal();

		decay_here_to_view = decay_here_to_view.cwiseProduct(
			Colorf(1, 1, 1) - decay_scatter);
	}
	assert(radiance[0] >= 0 && radiance[1] >= 0 && radiance[2] >= 0);
	radiance /= 100;
	return radiance;
}
RGB SubsurfacePathtracer::trace(Ray p_ray, Vector3d cameraPos, int p_depth) {

	RGB radiance(0,0,0);
	RGB localRadiance(0,0,0);
	RayIntersection nearestRayInt;
	p_depth++;
	
	bool intersected = false;

	if(scene->kdTree == NULL) {
		intersected = p_ray.nearestIntersection(scene->getObjects(), scene->getObjectCount(), &nearestRayInt);
	} else {
		intersected = scene->kdTree->nearestIntersection(&p_ray, &nearestRayInt);
	}

	if(intersected) {
		if(!(nearestRayInt.object->getShader()->isLight() && p_ray.getDiffuse())) {
			//local ilumination:
			Vector3d viewVec = cameraPos - nearestRayInt.point;
			viewVec.normalize();
			localRadiance = nearestRayInt.object->getShader()->getDiffuseRadiance(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, scene);

			radiance = localRadiance;

			if(nearestRayInt.object->getShader()->hasSubsurface()) {
				radiance = radiance + subsurface(&nearestRayInt, &p_ray);
				//return subsurface(&nearestRayInt, &p_ray);
			}

			int outVecsCount = 0;
			RGB indirectRadiance;

			if(p_depth == 1) {
				for(int i = 0; i < 5; i++) {
					if(p_depth < maxDepth) {
						Ray outRays[10];
						RGB values[10];
						outVecsCount = nearestRayInt.object->getShader()->getBRDFSampledRays(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, p_ray.getDir(), outRays, values);
						
						for(int s = 0; s < outVecsCount; s++) {
							Ray ray = outRays[s];
							indirectRadiance = indirectRadiance + (trace(ray, cameraPos, p_depth) * values[s]) ;
						}
					}

					indirectRadiance;
				}

				indirectRadiance = indirectRadiance / 5;
			} else {
				if(p_depth < maxDepth) {
					Ray outRays[10];
					RGB values[10];
					outVecsCount = nearestRayInt.object->getShader()->getBRDFSampledRays(nearestRayInt.object, nearestRayInt.point, nearestRayInt.normal, nearestRayInt.uv, viewVec, p_ray.getDir(), outRays, values);
					
					for(int s = 0; s < outVecsCount; s++) {
						Ray ray = outRays[s];
						indirectRadiance = indirectRadiance + (trace(ray, cameraPos, p_depth) * values[s]) ;
					}
				}	
			}

			if(outVecsCount > 0) {
				radiance =  radiance + indirectRadiance;
			}

		}
	} else if(scene->getBackground() != NULL) {
		radiance = scene->getBackground()->getRadianceAt(p_ray.getPoint(), p_ray.getPointAt(FAR_AWAY));
	}

	return radiance;
}
Ejemplo n.º 30
0
Imath::C3f radiance(Scene& scene, Ray& ray, Imath::Rand48& rnd, const int depth)
{
	Imath::V3d intersection_point, intersection_normal;
	int obj_id;
	if (!scene.intersect(ray, intersection_point, intersection_normal, obj_id))
	{
		return scene.bgColor;
	}

	Geometry geom = scene.geometries[obj_id];

	Imath::V3d orienting_normal = intersection_normal;
	if ((intersection_normal ^ ray.dir) > 0.0)
	{
		orienting_normal *= -1.0;
	}

	if (depth > LIMIT_DEPTH)
	{
		return geom.emission;
	}

	float reflect_ratio = (5.0f - static_cast<float>(depth)) / 5.0f;

	Imath::C3f inc_rad(0,0,0), weight(1,1,1);

	switch (geom.reflection)
	{
	case Reflection::Diffuse:
	{
		Imath::V3d w, u, v;
		w = orienting_normal;
		if (fabs(w.x) > 0.0000009)
		{
			u = (Imath::V3d(0.0, 1.0, 0.0) % w).normalized();
		}
		else
		{
			u = (Imath::V3d(1.0, 0.0, 0.0) % w).normalized();
		}
		v = w % u;
		double r1 = 2.0 * M_PI * rnd.nextf();
		double r2 = rnd.nextf();
		double rr2 = sqrt(r2);
		ray.pos = intersection_point;
		ray.dir = (u * cos(r1) * rr2 + v * sin(r1) * rr2 + w * sqrt(1.0 - r2)).normalized();
		inc_rad = radiance(scene, ray, rnd, depth + 1);
		weight = geom.color * reflect_ratio;
	}
		break;

	case Reflection::Specular:
		ray.pos = intersection_point;
		ray.dir -= intersection_normal * 2.0 * (intersection_normal ^ ray.dir);
		inc_rad = radiance(scene, ray, rnd, depth + 1);
		weight = geom.color * reflect_ratio;
		break;

	case Reflection::Refraction:
		bool into = (orienting_normal ^ intersection_normal) > 0.0;

		double default_refraction = 1.0;
		double object_refraction = 1.5;
		double ray_refraction;
		if (into)
		{
			ray_refraction = default_refraction / object_refraction;
		}
		else
		{
			ray_refraction = object_refraction / default_refraction;
		}
		double incident_dot = ray.dir ^ orienting_normal;
		double critical_factor = 1.0 - pow(ray_refraction, 2) * (1.0 - pow(incident_dot,2));

		Ray reflection_ray(intersection_point, ray.dir - intersection_normal * 2.0 * (intersection_normal ^ ray.dir));
		Ray refraction_ray(intersection_point, (ray.dir * ray_refraction - intersection_normal * (into ? 1.0 : -1.0) * (incident_dot * ray_refraction + sqrt(critical_factor))).normalized());

		// total reflection
		if (critical_factor < 0.0)
		{
			inc_rad = radiance(scene, reflection_ray, rnd, depth + 1);
			weight = geom.color * reflect_ratio;
			break;
		}

		double a = object_refraction - default_refraction;
		double b = object_refraction + default_refraction;
		double vertical_incidence_factor = pow(a, 2) / pow(b, 2);
		double c = 1.0 - (into ? -1.0 * incident_dot : (refraction_ray.dir ^ -1.0 * orienting_normal));
		double fresnel_incidence_factor = vertical_incidence_factor + (1.0 - vertical_incidence_factor) * pow(c,5);
		double radiance_scale = pow(ray_refraction, 2.0);
		double refraction_factor = (1.0 - fresnel_incidence_factor) * radiance_scale;

		double probability = 0.75 + fresnel_incidence_factor;
		if (depth > 2)
		{
			if (rnd.nextf() < probability)
			{
				inc_rad = radiance(scene, reflection_ray, rnd, depth + 1) * fresnel_incidence_factor;
				weight = geom.color * reflect_ratio;
			}
			else
			{
				inc_rad = radiance(scene, refraction_ray, rnd, depth + 1) * refraction_factor;
				weight = geom.color * reflect_ratio;
			}
		}
		else
		{
			inc_rad = 
				radiance(scene, reflection_ray, rnd, depth + 1) * fresnel_incidence_factor +
				radiance(scene, refraction_ray, rnd, depth + 1) * refraction_factor;
			weight = geom.color * reflect_ratio;
		}		

		break;
	}

	return geom.emission + weight * inc_rad;

}