u_int64_t CPU_Worker::AdvancePhotonPath(u_int64_t photonTarget) { uint todoPhotonCount = 0; PhotonPath* livePhotonPaths = new PhotonPath[rayBuffer->GetSize()]; rayBuffer->Reset(); size_t initc = min((int) rayBuffer->GetSize(), (int) photonTarget); double start = WallClockTime(); for (size_t i = 0; i < initc; ++i) { int p = rayBuffer->ReserveRay(); Ray * b = &(rayBuffer->GetRayBuffer())[p]; engine->InitPhotonPath(engine->ss, &livePhotonPaths[i], b, seedBuffer[i]); } while (todoPhotonCount < photonTarget) { Intersect(rayBuffer); #ifndef __DEBUG omp_set_num_threads(config->max_threads); #pragma omp parallel for schedule(guided) #endif for (unsigned int i = 0; i < rayBuffer->GetRayCount(); ++i) { PhotonPath *photonPath = &livePhotonPaths[i]; Ray *ray = &rayBuffer->GetRayBuffer()[i]; RayHit *rayHit = &rayBuffer->GetHitBuffer()[i]; if (photonPath->done == true) { continue; } if (rayHit->Miss()) { photonPath->done = true; } else { // Something was hit Point hitPoint; Spectrum surfaceColor; Normal N, shadeN; if (engine->GetHitPointInformation(engine->ss, ray, rayHit, hitPoint, surfaceColor, N, shadeN)) continue; const unsigned int currentTriangleIndex = rayHit->index; const unsigned int currentMeshIndex = engine->ss->meshIDs[currentTriangleIndex]; POINTERFREESCENE::Material *hitPointMat = &engine->ss->materials[engine->ss->meshMats[currentMeshIndex]]; uint matType = hitPointMat->type; if (matType == MAT_AREALIGHT) { photonPath->done = true; } else { float fPdf; Vector wi; Vector wo = -ray->d; bool specularBounce = true; float u0 = getFloatRNG(seedBuffer[i]); float u1 = getFloatRNG(seedBuffer[i]); float u2 = getFloatRNG(seedBuffer[i]); Spectrum f; switch (matType) { case MAT_MATTE: engine->ss->Matte_Sample_f(&hitPointMat->param.matte, &wo, &wi, &fPdf, &f, &shadeN, u0, u1, &specularBounce); f *= surfaceColor; break; case MAT_MIRROR: engine->ss->Mirror_Sample_f(&hitPointMat->param.mirror, &wo, &wi, &fPdf, &f, &shadeN, &specularBounce); f *= surfaceColor; break; case MAT_GLASS: engine->ss->Glass_Sample_f(&hitPointMat->param.glass, &wo, &wi, &fPdf, &f, &N, &shadeN, u0, &specularBounce); f *= surfaceColor; break; case MAT_MATTEMIRROR: engine->ss->MatteMirror_Sample_f(&hitPointMat->param.matteMirror, &wo, &wi, &fPdf, &f, &shadeN, u0, u1, u2, &specularBounce); f *= surfaceColor; break; case MAT_METAL: engine->ss->Metal_Sample_f(&hitPointMat->param.metal, &wo, &wi, &fPdf, &f, &shadeN, u0, u1, &specularBounce); f *= surfaceColor; break; case MAT_MATTEMETAL: engine->ss->MatteMetal_Sample_f(&hitPointMat->param.matteMetal, &wo, &wi, &fPdf, &f, &shadeN, u0, u1, u2, &specularBounce); f *= surfaceColor; break; case MAT_ALLOY: engine->ss->Alloy_Sample_f(&hitPointMat->param.alloy, &wo, &wi, &fPdf, &f, &shadeN, u0, u1, u2, &specularBounce); f *= surfaceColor; break; case MAT_ARCHGLASS: engine->ss->ArchGlass_Sample_f(&hitPointMat->param.archGlass, &wo, &wi, &fPdf, &f, &N, &shadeN, u0, &specularBounce); f *= surfaceColor; break; case MAT_NULL: wi = ray->d; specularBounce = 1; fPdf = 1.f; break; default: // Huston, we have a problem... specularBounce = 1; fPdf = 0.f; break; } if (!specularBounce) // if difuse lookupA->AddFlux(engine->ss, engine->alpha, hitPoint, shadeN, -ray->d, photonPath->flux, currentPhotonRadius2); if (photonPath->depth < MAX_PHOTON_PATH_DEPTH) { // Build the next vertex path ray if ((fPdf <= 0.f) || f.Black()) { photonPath->done = true; } else { photonPath->depth++; photonPath->flux *= f / fPdf; // Russian Roulette const float p = 0.75f; if (photonPath->depth < 3) { *ray = Ray(hitPoint, wi); } else if (getFloatRNG(seedBuffer[i]) < p) { photonPath->flux /= p; *ray = Ray(hitPoint, wi); } else { photonPath->done = true; } } } else { photonPath->done = true; } } } } uint oldc = rayBuffer->GetRayCount(); rayBuffer->Reset(); for (unsigned int i = 0; i < oldc; ++i) { PhotonPath *photonPath = &livePhotonPaths[i]; Ray *ray = &rayBuffer->GetRayBuffer()[i]; if (photonPath->done && todoPhotonCount < photonTarget) { todoPhotonCount++; Ray n; engine->InitPhotonPath(engine->ss, photonPath, &n, seedBuffer[i]); livePhotonPaths[i].done = false; size_t p = rayBuffer->AddRay(n); livePhotonPaths[p] = *photonPath; } else if (!photonPath->done) { rayBuffer->AddRay(*ray); } } } // float MPhotonsSec = todoPhotonCount / ((WallClockTime()-start) * 1000000.f); //printf("\nRate: %.3f MPhotons/sec\n",MPhotonsSec); profiler->addPhotonTracingTime(WallClockTime() - start); profiler->addPhotonsTraced(todoPhotonCount); rayBuffer->Reset(); return todoPhotonCount; }
void advance_eye_paths_impl( HitPointPosition* const hit_points, //const unsigned hit_points_count EyePath* const eye_paths, const unsigned eye_paths_count, Seed* const seed_buffer, //const unsigned seed_buffer_count, const PtrFreeScene* const scene, const unsigned max_eye_path_depth, const unsigned num_threads) { #pragma omp parallel for num_threads(num_threads) for(unsigned i = 0; i < eye_paths_count; ++i) { EyePath& eye_path = eye_paths[i]; Ray& ray = eye_path.ray; // rays[i]; RayHit hit; // = hits[i]; while(!eye_path.done) { hit.SetMiss(); scene->intersect(ray, hit); if (eye_path.depth > max_eye_path_depth) { // make it done HitPointPosition& hp = hit_points[eye_path.sample_index]; hp.type = CONSTANT_COLOR; hp.scr_x = eye_path.scr_x; hp.scr_y = eye_path.scr_y; hp.throughput = Spectrum(); eye_path.done = true; } else { eye_path.depth++; } if (hit.Miss()) { // add a hit point HitPointPosition& hp = hit_points[eye_path.sample_index]; hp.type = CONSTANT_COLOR; hp.scr_x = eye_path.scr_x; hp.scr_y = eye_path.scr_y; if (scene->infinite_light.exists || scene->sun_light.exists || scene->sky_light.exists) { if (scene->infinite_light.exists) { // TODO check this helpers::infinite_light_le(hp.throughput, eye_path.ray.d, scene->infinite_light, scene->infinite_light_map); } if (scene->sun_light.exists) { // TODO check this helpers::sun_light_le(hp.throughput, eye_path.ray.d, scene->sun_light); } if (scene->sky_light.exists) { // TODO check this helpers::sky_light_le(hp.throughput, eye_path.ray.d, scene->sky_light); } hp.throughput *= eye_path.flux; } else { hp.throughput = Spectrum(); } eye_path.done = true; } else { // something was hit Point hit_point; Spectrum surface_color; Normal N, shade_N; if (helpers::get_hit_point_information(scene, eye_path.ray, hit, hit_point, surface_color, N, shade_N)) { continue; } // get the material const unsigned current_triangle_index = hit.index; const unsigned current_mesh_index = scene->mesh_ids[current_triangle_index]; const unsigned material_index = scene->mesh_materials[current_mesh_index]; const Material& hit_point_mat = scene->materials[material_index]; unsigned mat_type = hit_point_mat.type; if (mat_type == MAT_AREALIGHT) { // add a hit point HitPointPosition &hp = hit_points[eye_path.sample_index]; hp.type = CONSTANT_COLOR; hp.scr_x = eye_path.scr_x; hp.scr_y = eye_path.scr_y; Vector md = - eye_path.ray.d; helpers::area_light_le(hp.throughput, md, N, hit_point_mat.param.area_light); hp.throughput *= eye_path.flux; eye_path.done = true; } else { Vector wo = - eye_path.ray.d; float material_pdf; Vector wi; bool specular_material = true; float u0 = floatRNG(seed_buffer[eye_path.sample_index]); float u1 = floatRNG(seed_buffer[eye_path.sample_index]); float u2 = floatRNG(seed_buffer[eye_path.sample_index]); Spectrum f; helpers::generic_material_sample_f(hit_point_mat, wo, wi, N, shade_N, u0, u1, u2, material_pdf, f, specular_material); f *= surface_color; if ((material_pdf <= 0.f) || f.Black()) { // add a hit point HitPointPosition& hp = hit_points[eye_path.sample_index]; hp.type = CONSTANT_COLOR; hp.scr_x = eye_path.scr_x; hp.scr_y = eye_path.scr_y; hp.throughput = Spectrum(); } else if (specular_material || (!hit_point_mat.diffuse)) { eye_path.flux *= f / material_pdf; eye_path.ray = Ray(hit_point, wi); } else { // add a hit point HitPointPosition& hp = hit_points[eye_path.sample_index]; hp.type = SURFACE; hp.scr_x = eye_path.scr_x; hp.scr_y = eye_path.scr_y; hp.material_ss = material_index; hp.throughput = eye_path.flux * surface_color; hp.position = hit_point; hp.wo = - eye_path.ray.d; hp.normal = shade_N; eye_path.done = true; } } } } } }