void PhotonMapping::TracePhoton(const Vec3f &position, const Vec3f &direction, 
				const Vec3f &energy, int iter) {
  
  if(iter>args->num_bounces){
    return;
  }

  Hit h = Hit();
  Ray R = Ray(position, direction);
  bool intersect = raytracer->CastRay(R, h, false);
  if(!intersect){
    return;
  }
  Material *m = h.getMaterial();
  Vec3f normal = h.getNormal();
  Vec3f point = R.pointAtParameter(h.getT());
  Vec3f opDirec = direction;
  opDirec.Negate();
  opDirec.Normalize();
  Vec3f diffuse = m->getDiffuseColor(), reflec = m->getReflectiveColor();
  double diffuseAnswer = diffuse.x()+diffuse.y()+diffuse.z();
  double reflecAnswer = reflec.x()+reflec.y()+reflec.z();
  double total = reflecAnswer+diffuseAnswer;
  diffuseAnswer /= total;
  reflecAnswer /= total;
  double seed = GLOBAL_mtrand.rand();
  if(seed <= diffuseAnswer && seed >= 0){
    Vec3f newEnergy = energy * diffuse;
    Vec3f newPosition = point;
    Vec3f newDirection = Vec3f(GLOBAL_mtrand.rand(),GLOBAL_mtrand.rand(),GLOBAL_mtrand.rand());
    newDirection.Normalize();
    Photon answer = Photon(point,opDirec,newEnergy,iter+1);
    kdtree->AddPhoton(answer);
    TracePhoton(newPosition, newDirection, newEnergy, iter+1);
  }
  else if(seed>diffuseAnswer && seed <= 1){
    Vec3f newEnergy = energy * reflec;
    Vec3f newPosition = point;
    Vec3f newDirection = direction - 2 * direction.Dot3(normal) * normal;
    Photon answer = Photon(point,opDirec,newEnergy,iter+1);
    kdtree->AddPhoton(answer);
    TracePhoton(newPosition, newDirection, newEnergy, iter+1);
  }
  // ==============================================
  // ASSIGNMENT: IMPLEMENT RECURSIVE PHOTON TRACING
  // ==============================================

  // Trace the photon through the scene.  At each diffuse or
  // reflective bounce, store the photon in the kd tree.

  // One optimization is to *not* store the first bounce, since that
  // direct light can be efficiently computed using classic ray
  // tracing.



}
Пример #2
0
void PhotonMappingRenderer::GenericPhotonMapGeneration(PhotonKdtree& photonMap, int totalPhotons)
{
    float totalLightIntensity = 0.f;
    size_t totalLights = storedScene->GetTotalLights();
    for (size_t i = 0; i < totalLights; ++i) {
        const Light* currentLight = storedScene->GetLightObject(i);
        if (!currentLight) {
            continue;
        }
        totalLightIntensity = glm::length(currentLight->GetLightColor());
    }

    // Shoot photons -- number of photons for light is proportional to the light's intensity relative to the total light intensity of the scene.
    for (size_t i = 0; i < totalLights; ++i) {
        const Light* currentLight = storedScene->GetLightObject(i);
        if (!currentLight) {
            continue;
        }

        const float proportion = glm::length(currentLight->GetLightColor()) / totalLightIntensity;
        const int totalPhotonsForLight = static_cast<const int>(proportion * totalPhotons);
        const glm::vec3 photonIntensity = currentLight->GetLightColor() / static_cast<float>(totalPhotonsForLight);
        for (int j = 0; j < totalPhotonsForLight; ++j) {
            Ray photonRay;
            std::vector<char> path;
            path.push_back('L');
            currentLight->GenerateRandomPhotonRay(photonRay);
            TracePhoton(photonMap, &photonRay, photonIntensity, path, 1.f, maxPhotonBounces);
        }
    }
}
void PhotonMapping::TracePhoton(const Vec3f &position, const Vec3f &direction, 
				const Vec3f &energy, int iter) {


  // ==============================================
  // ASSIGNMENT: IMPLEMENT RECURSIVE PHOTON TRACING
  // ==============================================

  // Trace the photon through the scene.  At each diffuse or
  // reflective bounce, store the photon in the kd tree.

  // One optimization is to *not* store the first bounce, since that
  // direct light can be efficiently computed using classic ray
  // tracing.

  //do ray cast
  Ray r(position,direction*(1/direction.Length()));
  Hit h;
  raytracer->CastRay(r,h,true);
  if (h.getT()>1000)
	  return;
  MTRand mtrand;
  Vec3f refl = h.getMaterial()->getReflectiveColor();
  Vec3f diff = h.getMaterial()->getDiffuseColor();
  double ran=mtrand.rand();
  if (iter==0)
	  ran= mtrand.rand(refl.Length()+diff.Length());
  //std::cout<<iter<<" "<<h.getT()<<" "<<refl.Length()+diff.Length()<<std::endl;
  //send reflective photon
  if (iter<args->num_bounces&&ran<=refl.Length())
	  TracePhoton(r.pointAtParameter(h.getT()),r.getDirection()-2*(r.getDirection().Dot3(h.getNormal()))*h.getNormal(),energy,iter+1);
  else if (iter<args->num_bounces&&ran<=refl.Length()+diff.Length())
	  TracePhoton(r.pointAtParameter(h.getT()),RandomDiffuseDirection(h.getNormal()),energy,iter+1);
  else
  {
	  Photon p(position,direction,energy,iter);
	  kdtree->AddPhoton(p);
  }


}
Пример #4
0
TracePhoton RectangularLight::samplePhoton() {
	std::vector<Vec2f> samples(2);
	randomSampler->generateSamples(2, samples);

	Mat44f rot = Mat44f::I();
	rot.rotateTo(Vec3f(0,0,1), Vec3f(0,-1,0));
	
	Vec3f warpedPoint = Vec3f(size.x*samples[0].x + minPosition.x, minPosition.y, size.y*samples[0].y + minPosition.z);
	Vec3f warpedDirection = rot * cosineWarping->warp(samples[1]);

	TracePhoton photon = TracePhoton(warpedPoint, warpedDirection, power);

	return photon;
}
void PhotonMapping::TracePhotons() {
  std::cout << "trace photons" << std::endl;

  // first, throw away any existing photons
  delete kdtree;

  // consruct a kdtree to store the photons
  BoundingBox *bb = mesh->getBoundingBox();
  Vec3f min = bb->getMin();
  Vec3f max = bb->getMax();
  Vec3f diff = max-min;
  min -= 0.001*diff;
  max += 0.001*diff;
  kdtree = new KDTree(BoundingBox(min,max));

  // photons emanate from the light sources
  const std::vector<Face*>& lights = mesh->getLights();

  // compute the total area of the lights
  double total_lights_area = 0;
  for (unsigned int i = 0; i < lights.size(); i++) {
    total_lights_area += lights[i]->getArea();
  }

  // shoot a constant number of photons per unit area of light source
  // (alternatively, this could be based on the total energy of each light)
  for (unsigned int i = 0; i < lights.size(); i++) {  
    double my_area = lights[i]->getArea();
    int num = args->num_photons_to_shoot * my_area / total_lights_area;
    // the initial energy for this photon
    Vec3f energy = my_area/double(num) * lights[i]->getMaterial()->getEmittedColor();
    Vec3f normal = lights[i]->computeNormal();
    for (int j = 0; j < num; j++) {
      Vec3f start = lights[i]->RandomPoint();
      // the initial direction for this photon (for diffuse light sources)
      Vec3f direction = RandomDiffuseDirection(normal);
      TracePhoton(start,direction,energy,0);
    }
  }
}
Пример #6
0
void GLCanvas::keyboard(unsigned char key, int x, int y) {
	args->raytracing_animation = false;
	switch (key) {
		// RAYTRACING STUFF
	case 'r':	case 'R':
	{
		// animate raytracing of the scene
		args->gather_indirect=false;
		args->raytracing_animation = !args->raytracing_animation;
		if (args->raytracing_animation) {
			// time the animation
			rendering_time = std::chrono::duration_cast<std::chrono::microseconds>(
				std::chrono::system_clock::now().time_since_epoch()).count();
			
			raytracing_skip = 1; //my_max(args->width,args->height) / 10;
			raytracing_x = 0;
			raytracing_y = 0;
			display(); // clear out any old rendering
			printf ("raytracing animation started, press 'R' to stop\n");
		} else {
			printf ("raytracing animation stopped, press 'R' to start\n");		
			// Print time to render
			rendering_time = std::chrono::duration_cast<std::chrono::microseconds>(
				std::chrono::system_clock::now().time_since_epoch()).count() 
				- rendering_time;
			std::cout << "Rendering completed in " << rendering_time/1000000.0
					<< " seconds." << std::endl;
		}
		break;
	}
	case 't':	case 'T': {
		// visualize the ray tree for the pixel at the current mouse position
		int i = x;
		int j = glutGet(GLUT_WINDOW_HEIGHT)-y;
		RayTree::Activate();
		raytracing_skip = 1;
		//TraceRay(i,j);
		//photon_mapping->setupVBOs();
		//photon_mapping->initializeVBOs();
		std::cout << "about to trace photons " << std::endl;
		TracePhoton(i,j);
		//photon_mapping->drawVBOs();
		//RayTree::drawVBOs();
		RayTree::Deactivate();
		// redraw
		std::cout << "about to call setup VBOs after trace photons" << std::endl;
		RayTree::setupVBOs();
		radiosity->setupVBOs();
		photon_mapping->setupVBOs();


		glutPostRedisplay();
		break; 
	}

	case 'l':	case 'L': { 
		// toggle photon rendering
		args->render_photons = !args->render_photons;
		glutPostRedisplay();
		break; }
	case 'k':	case 'K': { 
		// toggle photon rendering
		args->render_kdtree = !args->render_kdtree;
		glutPostRedisplay();
		break; }
	case 'p':	case 'P': { 
		// toggle photon rendering
		photon_mapping->TracePhotons();
		
		// TODO: remove
		//photon_mapping->printKDTree();
		
		photon_mapping->setupVBOs();
		RayTree::setupVBOs();
		glutPostRedisplay();
		break; }
	case 'g':	case 'G': { 
		args->gather_indirect = true;
		args->raytracing_animation = !args->raytracing_animation;
		if (args->raytracing_animation) {
			// time the animation
			rendering_time = 
				std::chrono::duration_cast<std::chrono::microseconds>(
				std::chrono::system_clock::now().time_since_epoch()).count();

			raytracing_x = 0;
			raytracing_y = 0;
			raytracing_skip = 1;//my_max(args->width,args->height) / 10;

			display(); // clear out any old rendering
			printf ("photon mapping animation started, press 'G' to stop\n");
		} else {
			printf ("photon mapping animation stopped, press 'G' to start\n");		
			// Print time to render
			rendering_time = std::chrono::duration_cast<std::chrono::microseconds>(
				std::chrono::system_clock::now().time_since_epoch()).count() 
				- rendering_time;
			std::cout << "Rendering stopped after " << rendering_time/1000000.0 
					<< " seconds." << std::endl;
		}
		break; 
	}
		
	case 's': case 'S':
	{
		// subdivide the mesh for radiosity
		radiosity->Cleanup();
		radiosity->getMesh()->Subdivision();
		radiosity->Reset();
		radiosity->setupVBOs();
		glutPostRedisplay();
		break;
	}
		// VISUALIZATIONS
	case 'w':	case 'W':
	{
		// render wireframe mode
		args->wireframe = !args->wireframe;
		glutPostRedisplay();
		break;
	}
	case 'v': case 'V':
	{
		std::cout << "RENDER_MATERIALS is the only mode\n";
		break;
	}
	case 'q':	case 'Q':
	{
		// quit
		delete GLCanvas::photon_mapping;
		delete GLCanvas::raytracer;
		delete GLCanvas::radiosity;
		delete GLCanvas::mesh;
		exit(0);
		break;
	}
	default:
		printf("UNKNOWN KEYBOARD INPUT	'%c'\n", key);
	}
}
void PhotonMappingRenderer::TracePhoton(PhotonKdtree& photonMap, Ray* photonRay, glm::vec3 lightIntensity,
                                        std::vector<char>& path, float currentIOR, int remainingBounces)
{

    // check the recursive base case
    if (remainingBounces < 0)
    {
        return;
    }

    assert(photonRay);
    IntersectionState state(0, 0);
    state.currentIOR = currentIOR;

    // Trace the photon ray and test for intersections
    bool didIntersect = storedScene->Trace(photonRay, &state);

    if (!didIntersect)
    {
        return;
    }

    // Get the normal to the intersection
    glm::vec3 normal = state.ComputeNormal();

    // Move the ray to the intersection point + a little offset
    glm::vec3 intersectionPoint = state.intersectionRay.GetRayPosition(state.intersectionT);
    photonRay->SetRayPosition(intersectionPoint + normal * SMALL_EPSILON);

    if (path.size() > 1)
    {
        // This photon did NOT come directly from the light, so
        // create and store a new Photon in the photon map

        Ray toLightRay(glm::vec3(photonRay->GetPosition()), -photonRay->GetRayDirection(), photonRay->GetMaxT());

        Photon myPhoton;
        myPhoton.position = glm::vec3(photonRay->GetPosition());
        myPhoton.intensity = lightIntensity;
        myPhoton.toLightRay = toLightRay;

        photonMap.insert(myPhoton);
    }

    // --------determine whether this photon is scattered or absorbed--------

    const MeshObject* hitMeshObject = state.intersectedPrimitive->GetParentMeshObject();
    const Material* hitMaterial = hitMeshObject->GetMaterial();

    glm::vec3 diffuseResponse = hitMaterial->GetBaseDiffuseReflection();

    // the probability of reflection is the max of the RGB components of the diffuse response

    float max = diffuseResponse.x;
    if (diffuseResponse.y > max)
    {
        max = diffuseResponse.y;
    }

    if (diffuseResponse.z > max)
    {
        max = diffuseResponse.z;
    }

    // 0 to RAND_MAX
    float rand_f = static_cast<float>(rand());

    // 0 to 1
    rand_f /= RAND_MAX;

    if (rand_f > max)
    {
        // photon absorbed
        return;
    }

    // ------scatter the photon------

    // sample the hemisphere around the point in order to
    // pick a diffuse reflection direction

    // 0 to RAND_MAX
    float u1 = static_cast<float>(rand());
    float u2 = static_cast<float>(rand());

    // 0 to 1
    u1 /= RAND_MAX;
    u2 /= RAND_MAX;

    float r = sqrt(u1);
    float theta = 2 * PI * u2;

    float x = r * cos(theta);
    float y = r * sin(theta);
    float z = sqrt(1 - u1);

    glm::vec3 newDir = glm::normalize(glm::vec3(x, y, z));

    // ---transform from tangent space to world space---


    // pick one of (1, 0, 0) (0, 1, 0) (0, 0, 1) as long as
    // dot product is not close to 1 (therefore not parallel)
    // to cross the normal with

    glm::vec3 candidate(1.f, 0.f, 0.f);

    float dot = glm::dot(normal, candidate);
    if (dot > 0.9)
    {
        candidate = glm::vec3(0.f, 1.f, 0.f);
    }

    glm::vec3 tangent = glm::cross(normal, candidate);
    glm::vec3 bitangent = glm::cross(normal, tangent);

    // construct 3x3 matrix where columns of the matrix are the
    // tangent, bitangent, and normal vectors (in that order)
    glm::mat3 mat(tangent, bitangent, normal);

    // multiply 3x3 matrix by the newDir vector in the previous step
    // to get the diffuse reflection ray direction in world space
    glm::vec3 worldDir = mat * newDir;

    photonRay->SetRayDirection(worldDir);

    // append to path vector, decrement remaining bounces
    path.push_back('L');
    remainingBounces--;

    // recursive call
    TracePhoton(photonMap, photonRay, lightIntensity, path, currentIOR, remainingBounces);
}