Пример #1
0
// 鏡面反射
Color PathTracer::Radiance_Specular(const Scene &scene, const Ray &ray, Random &rnd, const int depth, Scene::IntersectionInformation &intersect, const Vector3 &normal, double russian_roulette_prob) {
  Vector3 reflected_dir(ray.dir - normal*2*ray.dir.dot(normal));
  reflected_dir.normalize();

  // 間接光の評価
  Ray newray(intersect.hit.position, reflected_dir);
  Color income = Radiance(scene, newray, rnd, depth+1);

  // 直接光の評価
  Scene::IntersectionInformation newhit;
  if (m_performNextEventEstimation && scene.CheckIntersection(newray, newhit)) {
    income += newhit.object->material.emission;
  }

  Color weight = intersect.texturedHitpointColor / russian_roulette_prob;
  return Vector3(weight.x*income.x, weight.y*income.y, weight.z*income.z);

}
Пример #2
0
Color PathTracer::Radiance(const Scene &scene, const Ray &ray, Random &rnd, const int depth) {
  Scene::IntersectionInformation intersect;

  m_checkIntersectionCount++;
  bool intersected = scene.CheckIntersection(ray, intersect);

  Vector3 normal;

  if (intersected) {
    normal = intersect.hit.normal.dot(ray.dir) < 0.0 ? intersect.hit.normal : intersect.hit.normal * -1.0;
  }

  Color income;// = DirectRadiance(scene, ray, rnd, depth, intersected, intersect, normal);
  income += Radiance_internal(scene, ray, rnd, depth, intersected, intersect, normal);


  return income;
}
Пример #3
0
// 屈折面
Color PathTracer::Radiance_Refraction(const Scene &scene, const Ray &ray, Random &rnd, const int depth, Scene::IntersectionInformation &intersect, const Vector3 &normal, double russian_roulette_prob) {
  bool into = intersect.hit.normal.dot(normal) > 0.0;

  Vector3 reflect_dir = ray.dir - normal*2*ray.dir.dot(normal);
  reflect_dir.normalize();
  double n_vacuum = REFRACTIVE_INDEX_VACUUM;
  double n_obj = intersect.object->material.refraction_rate;
  double n_ratio = into ? n_vacuum/n_obj : n_obj/n_vacuum;

  double dot = ray.dir.dot(normal);
  double cos2t = 1-n_ratio*n_ratio*(1-dot*dot);

  // 反射方向の直接光の評価
  Color reflect_direct;
  Ray reflect_ray(intersect.hit.position, reflect_dir);
  Scene::IntersectionInformation reflected_hit;
  if (m_performNextEventEstimation && scene.CheckIntersection(reflect_ray, reflected_hit)) {
    reflect_direct = reflected_hit.object->material.emission;
  }

  if (cos2t < 0) {
    // 全反射
    Color income = reflect_direct + Radiance(scene, Ray(intersect.hit.position, reflect_dir), rnd, depth+1);
    Color weight = intersect.object->material.color / russian_roulette_prob;
    return Vector3(weight.x*income.x, weight.y*income.y, weight.z*income.z);
  }

  // 屈折方向
  Vector3 refract_dir( ray.dir*n_ratio - intersect.hit.normal * (into ? 1.0 : -1.0) * (dot*n_ratio + sqrt(cos2t)) );
  refract_dir.normalize();
  const Ray refract_ray(intersect.hit.position, refract_dir);
  // 屈折方向の直接光の評価
  Color refract_direct;
  if (m_performNextEventEstimation && scene.CheckIntersection(refract_ray, reflected_hit)) {
    refract_direct = reflected_hit.object->material.emission;
  }

  // Fresnel の式
  double F0 = (n_obj-n_vacuum)*(n_obj-n_vacuum)/((n_obj+n_vacuum)*(n_obj+n_vacuum));
  double c = 1 - ( into ? -dot : -refract_dir.dot(normal) );  // 1-cosθ
  double Fr = F0 + (1-F0)*pow(c, 5.0);    // Fresnel (反射の割合)
  double n_ratio2 = n_ratio*n_ratio;  // 屈折前後での放射輝度の変化率
  double Tr = (1-Fr)*n_ratio2;        // 屈折直後→直前の割合

  Color income, weight;

  if (depth > 2) {
    // 反射 or 屈折のみ追跡
    const double reflect_prob = 0.1 + 0.8 * Fr;
    if (rnd.nextDouble() < reflect_prob) {
      // 反射
      income = (reflect_direct + Radiance(scene, Ray(intersect.hit.position, reflect_dir), rnd, depth+1)) * Fr;
      weight = intersect.texturedHitpointColor / (russian_roulette_prob * reflect_prob);
    } else {
      // 屈折
      income = (refract_direct + Radiance(scene, refract_ray, rnd, depth+1)) * Tr;
      weight = intersect.texturedHitpointColor / (russian_roulette_prob * (1 - reflect_prob));
    }
  } else {
    // 反射と屈折両方追跡
    m_omittedRayCount++;
    income =
      (reflect_direct + Radiance(scene, Ray(intersect.hit.position, reflect_dir), rnd, depth+1)) * Fr +
      (refract_direct + Radiance(scene, refract_ray, rnd, depth + 1)) *Tr;
    weight = intersect.texturedHitpointColor / russian_roulette_prob;
  }

  return /*intersect.object->material.emission +*/ Vector3(weight.x*income.x, weight.y*income.y, weight.z*income.z);
}
Пример #4
0
// 直接光による Radiance の評価
Color PathTracer::DirectRadiance_Lambert(const Scene &scene, const Ray &ray, Random &rnd, const int depth, const bool intersected, Scene::IntersectionInformation &intersect, const Vector3 &normal) {
  assert(intersected);

  // ライトに当たっていたら無視
  if (dynamic_cast<LightBase *>(intersect.object) != nullptr)
  {
    return Color(0, 0, 0);
  }

  const vector<LightBase *> &lights = scene.GetLights();
  if (lights.size() == 0) return scene.Background();

  // pick a random light according to light power
  double totalPower = 0.0;
  vector<double> eachLightProbability, accumulatedProbability;
  for (size_t i = 0; i < lights.size(); i++) {
    double power = lights[i]->TotalPower();
    eachLightProbability.push_back(power);
    accumulatedProbability.push_back(totalPower + power);
    totalPower += power;
  }

  // 確率へ正規化
  for (size_t i = 0; i < lights.size(); i++) {
    eachLightProbability[i] /= totalPower;
    accumulatedProbability[i] /= totalPower;
  }

  static const int NumberOfLightSamples = 1;
  Color income;

  for (int lightCount = 0; lightCount < NumberOfLightSamples; lightCount++) {

    double next = rnd.nextDouble();
    int index = 0;
    for (size_t i = 0; i < lights.size(); i++) {
      if (next <= accumulatedProbability[i]) {
        index = i; break;
      }
    }

    const LightBase *selectedLight = lights[index];

    // pick a one point
    Vector3 point, light_normal; double pdf = 0.0;
    //selectedLight->SampleOnePoint(point, light_normal, pdf, rnd);
    if (!selectedLight->SampleOnePointWithTargetPoint(point, light_normal, pdf, intersect.hit.position, rnd)) {
      continue;
    }

    Vector3 dir((point - intersect.hit.position)); dir.normalize();
    double cos_shita = dir.dot(normal);
    double light_cos_shita = -dir.dot(light_normal);
    if (cos_shita < 0 || light_cos_shita < 0) {
      // cannot reach to the light
      continue;
    }
  
    // check visibility
    Scene::IntersectionInformation hit;
    if (scene.CheckIntersection(Ray(intersect.hit.position, dir), hit)) {
      if (dynamic_cast<LightBase *>(hit.object) == selectedLight) {
        // visible
        // BRDF = color/PI
        double G = cos_shita * light_cos_shita / (hit.hit.distance * hit.hit.distance);
        Vector3 reflect_rate(intersect.texturedHitpointColor / PI * G / (pdf * eachLightProbability[index]));
        income.x += reflect_rate.x * hit.object->material.emission.x;
        income.y += reflect_rate.y * hit.object->material.emission.y;
        income.z += reflect_rate.z * hit.object->material.emission.z;
        // direct_illum = 1/N*ΣL_e*BRDF*G*V/pdf(light)
        m_hitToLightCount++;
      }
    }
    m_omittedRayCount++;
  }

  return income / NumberOfLightSamples;
}