示例#1
0
Color PathTracer::Radiance_internal(const Scene &scene, const Ray &ray, Random &rnd, const int depth, const bool intersected, Scene::IntersectionInformation &intersect, const Vector3 &normal) {
  if (!intersected) {
    if (scene.GetIBL()) {
      //return scene.GetIBL()->Sample(ray);    // 正確に背景との衝突位置を計算する
      return scene.GetIBL()->Sample(ray.dir); // レイが原点から始まっているとみなして計算する
    } else {
      return scene.Background();
    }
  }

  Color &textured = intersect.texturedHitpointColor = GetTexturedColor(intersect.object->material, intersect.hit.uv);

  Color income;

  // この if 文を有効にすると、直接光のみ考慮するようになる
  //if (depth >= 1) {
  //  return intersect.object->material.emission;
  //}

  double russian_roulette_probability = std::max(textured.x, std::max(textured.y, textured.z)); // 適当
  if (depth > MaxDepth) {
    russian_roulette_probability *= pow(0.5, depth - MaxDepth);
  }
  if (depth > MinDepth) {
    if (rnd.nextDouble() >= russian_roulette_probability) {
      // 各 radiance を計算するときに直接光を計算しているので、
      // 「eye から直接 light に hit した場合」のみ、emission を income に加える
      if (depth == 0 || !m_performNextEventEstimation) {
        if (intersect.object->material.emission.lengthSq() != 0) {
          m_hitToLightCount++;
        }
        return intersect.object->material.emission;
      }
      return scene.Background();
    }
  } else {
    russian_roulette_probability = 1.0; // no roulette
  }

  switch (intersect.object->material.reflection_type) {
    case Material::REFLECTION_TYPE_LAMBERT:
      income = Radiance_Lambert(scene, ray, rnd, depth, intersect, normal, russian_roulette_probability);
      break;
    case Material::REFLECTION_TYPE_SPECULAR:
      income = Radiance_Specular(scene, ray, rnd, depth, intersect, normal, russian_roulette_probability);
      break;
    case Material::REFLECTION_TYPE_REFRACTION:
      income = Radiance_Refraction(scene, ray, rnd, depth, intersect, normal, russian_roulette_probability);
      break;
  }

  // 各 radiance を計算するときに直接光を計算しているので、
  // 「eye から直接 light に hit した場合」のみ、emission を income に加える
  if (depth == 0 || !m_performNextEventEstimation) {
    // --> eye から直接 light に hit し、 light 自身が反射率を持つ場合にここが有効になる
    income += intersect.object->material.emission;
    if (intersect.object->material.emission.lengthSq() != 0) {
      m_hitToLightCount++;
    }
  }

  return income;
}
示例#2
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;
}