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; }
// 直接光による 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; }