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 CPU_Worker::AdvanceEyePaths( RayBuffer *rayBuffer, EyePath* todoEyePaths, uint* eyePathIndexes) { const uint max = rayBuffer->GetRayCount(); omp_set_num_threads(config->max_threads); #pragma omp parallel for schedule(guided) for (uint i = 0; i < max; i++) { EyePath *eyePath = &todoEyePaths[eyePathIndexes[i]]; const RayHit *rayHit = &rayBuffer->GetHitBuffer()[i]; if (rayHit->Miss()) { // Add an hit point //HitPointInfo &hp = *(engine->GetHitPointInfo(eyePath->pixelIndex)); HitPointStaticInfo &hp = hitPointsStaticInfo_iterationCopy[eyePath->sampleIndex]; //HitPoint &hp = GetHitPoint(hitPointsIndex++); hp.type = CONSTANT_COLOR; hp.scrX = eyePath->scrX; hp.scrY = eyePath->scrY; // if (scene->infiniteLight) // hp.throughput = scene->infiniteLight->Le( // eyePath->ray.d) * eyePath->throughput; // else // hp.throughput = Spectrum(); if (ss->infiniteLight || ss->sunLight || ss->skyLight) { // hp.throughput = scene->infiniteLight->Le(eyePath->ray.d) * eyePath->throughput; if (ss->infiniteLight) ss->InfiniteLight_Le(&hp.throughput, &eyePath->ray.d, ss->infiniteLight, ss->infiniteLightMap); if (ss->sunLight) ss->SunLight_Le(&hp.throughput, &eyePath->ray.d, ss->sunLight); if (ss->skyLight) ss->SkyLight_Le(&hp.throughput, &eyePath->ray.d, ss->skyLight); hp.throughput *= eyePath->throughput; } else hp.throughput = Spectrum(); // Free the eye path //ihp.accumPhotonCount = 0; //ihp.accumReflectedFlux = Spectrum(); //ihp.photonCount = 0; //hp.reflectedFlux = Spectrum(); eyePath->done = true; //--todoEyePathCount; } else { // Something was hit Point hitPoint; Spectrum surfaceColor; Normal N, shadeN; if (engine->GetHitPointInformation(ss, &eyePath->ray, rayHit, hitPoint, surfaceColor, N, shadeN)) continue; // Get the material const unsigned int currentTriangleIndex = rayHit->index; const unsigned int currentMeshIndex = ss->meshIDs[currentTriangleIndex]; const uint materialIndex = ss->meshMats[currentMeshIndex]; POINTERFREESCENE::Material *hitPointMat = &ss->materials[materialIndex]; uint matType = hitPointMat->type; if (matType == MAT_AREALIGHT) { // Add an hit point //HitPointInfo &hp = *(engine->GetHitPointInfo( // eyePath->pixelIndex)); HitPointStaticInfo &hp = hitPointsStaticInfo_iterationCopy[eyePath->sampleIndex]; hp.type = CONSTANT_COLOR; hp.scrX = eyePath->scrX; hp.scrY = eyePath->scrY; //ihp.accumPhotonCount = 0; //ihp.accumReflectedFlux = Spectrum(); //ihp.photonCount = 0; //hp.reflectedFlux = Spectrum(); Vector md = -eyePath->ray.d; ss->AreaLight_Le(&hitPointMat->param.areaLight, &md, &N, &hp.throughput); hp.throughput *= eyePath->throughput; // Free the eye path eyePath->done = true; //--todoEyePathCount; } else { Vector wo = -eyePath->ray.d; float materialPdf; Vector wi; bool specularMaterial = true; float u0 = getFloatRNG(seedBuffer[eyePath->sampleIndex]); float u1 = getFloatRNG(seedBuffer[eyePath->sampleIndex]); float u2 = getFloatRNG(seedBuffer[eyePath->sampleIndex]); Spectrum f; switch (matType) { case MAT_MATTE: ss->Matte_Sample_f(&hitPointMat->param.matte, &wo, &wi, &materialPdf, &f, &shadeN, u0, u1, &specularMaterial); f *= surfaceColor; break; case MAT_MIRROR: ss->Mirror_Sample_f(&hitPointMat->param.mirror, &wo, &wi, &materialPdf, &f, &shadeN, &specularMaterial); f *= surfaceColor; break; case MAT_GLASS: ss->Glass_Sample_f(&hitPointMat->param.glass, &wo, &wi, &materialPdf, &f, &N, &shadeN, u0, &specularMaterial); f *= surfaceColor; break; case MAT_MATTEMIRROR: ss->MatteMirror_Sample_f(&hitPointMat->param.matteMirror, &wo, &wi, &materialPdf, &f, &shadeN, u0, u1, u2, &specularMaterial); f *= surfaceColor; break; case MAT_METAL: ss->Metal_Sample_f(&hitPointMat->param.metal, &wo, &wi, &materialPdf, &f, &shadeN, u0, u1, &specularMaterial); f *= surfaceColor; break; case MAT_MATTEMETAL: ss->MatteMetal_Sample_f(&hitPointMat->param.matteMetal, &wo, &wi, &materialPdf, &f, &shadeN, u0, u1, u2, &specularMaterial); f *= surfaceColor; break; case MAT_ALLOY: ss->Alloy_Sample_f(&hitPointMat->param.alloy, &wo, &wi, &materialPdf, &f, &shadeN, u0, u1, u2, &specularMaterial); f *= surfaceColor; break; case MAT_ARCHGLASS: ss->ArchGlass_Sample_f(&hitPointMat->param.archGlass, &wo, &wi, &materialPdf, &f, &N, &shadeN, u0, &specularMaterial); f *= surfaceColor; break; case MAT_NULL: wi = eyePath->ray.d; specularMaterial = 1; materialPdf = 1.f; // I have also to restore the original throughput //throughput = prevThroughput; break; default: // Huston, we have a problem... specularMaterial = 1; materialPdf = 0.f; break; } // if (f.r != f2.r || f.g != f2.g || f.b != f2.b) { // printf("d"); // } if ((materialPdf <= 0.f) || f.Black()) { // Add an hit point //HitPointInfo &hp = *(engine->GetHitPointInfo( // eyePath->pixelIndex)); HitPointStaticInfo &hp = hitPointsStaticInfo_iterationCopy[eyePath->sampleIndex]; hp.type = CONSTANT_COLOR; hp.scrX = eyePath->scrX; hp.scrY = eyePath->scrY; hp.throughput = Spectrum(); //ihp.accumPhotonCount = 0; //ihp.accumReflectedFlux = Spectrum(); //ihp.photonCount = 0; //hp.reflectedFlux = Spectrum(); // Free the eye path eyePath->done = true; //--todoEyePathCount; } else if (specularMaterial || (!hitPointMat->difuse)) { eyePath->throughput *= f / materialPdf; eyePath->ray = Ray(hitPoint, wi); } else { // Add an hit point //HitPointInfo &hp = *(engine->GetHitPointInfo( // eyePath->pixelIndex)); HitPointStaticInfo &hp = hitPointsStaticInfo_iterationCopy[eyePath->sampleIndex]; hp.type = SURFACE; hp.scrX = eyePath->scrX; hp.scrY = eyePath->scrY; //hp.material // = (SurfaceMaterial *) triMat; //ihp.accumPhotonCount = 0; //ihp.accumReflectedFlux = Spectrum(); //ihp.photonCount = 0; //hp.reflectedFlux = Spectrum(); hp.materialSS = materialIndex; hp.throughput = eyePath->throughput * surfaceColor; hp.position = hitPoint; hp.wo = -eyePath->ray.d; hp.normal = shadeN; // Free the eye path eyePath->done = true; //--todoEyePathCount; } } } } }
void Worker::BuildHitPoints(uint /*iteration*/) { const unsigned int width = engine->width; const unsigned int height = engine->height; const unsigned int superSampling = engine->superSampling; const unsigned int hitPointTotal = engine->hitPointTotal; //Seed* EyePathsSeeds = new Seed[hitPointTotal]; EyePath* todoEyePaths = new EyePath[hitPointTotal]; memset(hitPointsStaticInfo_iterationCopy, 0, sizeof(HitPointStaticInfo) * engine->hitPointTotal); #ifndef USE_SPPM memset(hitPoints_iterationCopy, 0, sizeof(HitPoint) * engine->hitPointTotal); #endif unsigned int hitPointsIndex = 0; // Generate eye rays //std::cerr << "Building eye paths rays with " << superSampling << "x" // << superSampling << " super-sampling:" << std::endl; //std::cerr << " 0/" << height << std::endl; // double lastPrintTime = WallClockTime(); const float invSuperSampling = 1.f / superSampling; for (unsigned int y = 0; y < height; ++y) { // if (WallClockTime() - lastPrintTime > 2.0) { // std::cerr << " " << y << "/" << height << std::endl; // lastPrintTime = WallClockTime(); // } //for all hitpoints for (unsigned int x = 0; x < width; ++x) { for (unsigned int sy = 0; sy < superSampling; ++sy) { for (unsigned int sx = 0; sx < superSampling; ++sx) { EyePath *eyePath = &todoEyePaths[hitPointsIndex]; //EyePathsSeeds[hitPointsIndex] = mwc(hitPointsIndex + deviceID); eyePath->scrX = x + (sx + getFloatRNG(seedBuffer[hitPointsIndex])) * invSuperSampling - 0.5f; eyePath->scrY = y + (sy + getFloatRNG(seedBuffer[hitPointsIndex])) * invSuperSampling - 0.5f; float u0 = getFloatRNG(seedBuffer[hitPointsIndex]); float u1 = getFloatRNG(seedBuffer[hitPointsIndex]); float u2 = getFloatRNG(seedBuffer[hitPointsIndex]); // scene->camera->GenerateRay(eyePath->scrX, // eyePath->scrY, width, height, &eyePath->ray, // u0, u1, u2); ss->GenerateRay(eyePath->scrX, eyePath->scrY, width, height, &eyePath->ray, u0, u1, u2, &ss->camera); eyePath->depth = 0; eyePath->throughput = Spectrum(1.f, 1.f, 1.f); eyePath->done = false; eyePath->splat = false; eyePath->sampleIndex = hitPointsIndex; hitPointsIndex++; } } } } // Iterate through all eye paths //std::cerr << "Building eye paths hit points: " << std::endl; // lastPrintTime = WallClockTime(); // Note: (todoEyePaths.size() > 0) is extremly slow to execute uint todoEyePathCount = hitPointTotal; uint chunk_counter = 0; //std::cerr << " " << todoEyePathCount / 1000 << "k eye paths left" // << std::endl; uint* eyePathIndexes = new uint[getRaybufferSize()]; while (todoEyePathCount > 0) { // if (WallClockTime() - lastPrintTime > 2.0) { // std::cerr << " " << todoEyePathCount / 1000 << "k eye paths left" << std::endl; // lastPrintTime = WallClockTime(); // } //std::vector<EyePath *>::iterator todoEyePathsIterator = // todoEyePaths.begin() + roundPointer; //transversing in chunks uint start = (chunk_counter / getRaybufferSize()) * getRaybufferSize(); uint end; if (hitPointTotal - start < getRaybufferSize()) end = hitPointTotal; else end = start + getRaybufferSize(); for (uint i = start; i < end; i++) { EyePath *eyePath = &todoEyePaths[i]; // Check if we reached the max path depth if (!eyePath->done && eyePath->depth > MAX_EYE_PATH_DEPTH) { // Add an hit point //HitPointInfo &hp = *(engine->GetHitPointInfo( // eyePath->pixelIndex)); HitPointStaticInfo &hp = hitPointsStaticInfo_iterationCopy[eyePath->sampleIndex]; hp.type = CONSTANT_COLOR; hp.scrX = eyePath->scrX; hp.scrY = eyePath->scrY; hp.throughput = Spectrum(); //ihp.accumPhotonCount = 0; //ihp.accumReflectedFlux = Spectrum(); //ihp.photonCount = 0; //hp.reflectedFlux = Spectrum(); eyePath->done = true; } else if (!eyePath->done) { eyePath->depth++; uint p = RaybufferAddRay(eyePath->ray); eyePathIndexes[p] = i; } if (eyePath->done && !eyePath->splat) { --todoEyePathCount; chunk_counter++; eyePath->splat = true; } //if (rayBuffer->IsFull()) // break; } if (getRayBufferRayCount() > 0) { IntersectRayBuffer(); //printf("%d\n",rayBuffer->GetRayCount()); AdvanceEyePaths(&todoEyePaths[0], eyePathIndexes); resetRayBuffer(); } } delete[] todoEyePaths; delete[] eyePathIndexes; }
void Worker::BuildHitPoints(uint iteration) { const unsigned int width = engine->width; const unsigned int height = engine->height; const unsigned int superSampling = engine->superSampling; const unsigned int hitPointTotal = engine->hitPointTotal; EyePath* todoEyePaths = new EyePath[hitPointTotal]; #ifndef USE_SPPM memset(HPsIterationRadianceFlux, 0, sizeof(HitPointRadianceFlux) * engine->hitPointTotal); #endif unsigned int hitPointsIndex = 0; const float invSuperSampling = 1.f / superSampling; for (unsigned int y = 0; y < height; ++y) { //for all hitpoints for (unsigned int x = 0; x < width; ++x) { for (unsigned int sy = 0; sy < superSampling; ++sy) { for (unsigned int sx = 0; sx < superSampling; ++sx) { EyePath *eyePath = &todoEyePaths[hitPointsIndex]; eyePath->scrX = x + (sx + getFloatRNG(seedBuffer[hitPointsIndex])) * invSuperSampling - 0.5f; eyePath->scrY = y + (sy + getFloatRNG(seedBuffer[hitPointsIndex])) * invSuperSampling - 0.5f; float u0 = getFloatRNG(seedBuffer[hitPointsIndex]); float u1 = getFloatRNG(seedBuffer[hitPointsIndex]); float u2 = getFloatRNG(seedBuffer[hitPointsIndex]); ss->GenerateRay(eyePath->scrX, eyePath->scrY, width, height, &eyePath->ray, u0, u1, u2, &ss->camera); eyePath->depth = 0; eyePath->throughput = Spectrum(1.f, 1.f, 1.f); eyePath->done = false; eyePath->splat = false; eyePath->sampleIndex = hitPointsIndex; hitPointsIndex++; } } } } uint todoEyePathCount = hitPointTotal; uint chunk_counter = 0; uint* eyePathIndexes = new uint[getRaybufferSize()]; resetRayBuffer(); while (todoEyePathCount > 0) { //transversing in chunks uint start = (chunk_counter / getRaybufferSize()) * getRaybufferSize(); uint end; if (hitPointTotal - start < getRaybufferSize()) end = hitPointTotal; else end = start + getRaybufferSize(); for (uint i = start; i < end; i++) { EyePath *eyePath = &todoEyePaths[i]; // Check if we reached the max path depth if (!eyePath->done && eyePath->depth > MAX_EYE_PATH_DEPTH) { // Add an hit point HitPointPositionInfo* hp = GetHitPointInfo(eyePath->sampleIndex); hp->type = CONSTANT_COLOR; hp->scrX = eyePath->scrX; hp->scrY = eyePath->scrY; hp->throughput = Spectrum(); eyePath->done = true; } else if (!eyePath->done) { eyePath->depth++; uint p = RaybufferAddRay(eyePath->ray); eyePathIndexes[p] = i; } if (eyePath->done && !eyePath->splat) { --todoEyePathCount; chunk_counter++; eyePath->splat = true; } } if (getRayBufferRayCount() > 0) { IntersectRayBuffer(); AdvanceEyePaths(&todoEyePaths[0], eyePathIndexes); resetRayBuffer(); } } delete[] todoEyePaths; delete[] eyePathIndexes; }
void DistrurbeSample(Path *p) { p->screenX += getFloatRNG(&p->seed) / 4.f; p->screenY += getFloatRNG(&p->seed) / 4.f; }
bool Shade(Path* path, Geometry *geometry, BVHAccel *bvh, const RayHit& rayHit) { uint tracedShadowRayCount; if (rayHit.index == 0xffffffffu) { return false; } // Something was hit unsigned int currentTriangleIndex = rayHit.index; RGB triInterpCol = geometry->triangles[currentTriangleIndex].InterpolateColor( geometry->vertColors, rayHit.b1, rayHit.b2); Normal shadeN = geometry->triangles[currentTriangleIndex].InterpolateNormal( geometry->vertNormals, rayHit.b1, rayHit.b2); // Calculate next step path->depth++; // Check if I have to stop if (path->depth >= MAX_PATH_DEPTH) { // Too depth, terminate the path return false; } else if (path->depth > 2) { // Russian Rulette, maximize cos const float p = min(1.f, triInterpCol.filter() * AbsDot(shadeN, path->pathRay.d)); if (p > getFloatRNG(&path->seed)) path->throughput /= p; else { // Terminate the path return false; } } //-------------------------------------------------------------------------- // Build the shadow ray //-------------------------------------------------------------------------- // Check if it is a light source float RdotShadeN = Dot(path->pathRay.d, shadeN); if (geometry->IsLight(currentTriangleIndex)) { // Check if we are on the right side of the light source if ((path->depth == 1) && (RdotShadeN < 0.f)) path->radiance += triInterpCol * path->throughput; // Terminate the path return false; } if (RdotShadeN > 0.f) { // Flip shade normal shadeN = -shadeN; } else RdotShadeN = -RdotShadeN; path->throughput *= RdotShadeN * triInterpCol; // Trace shadow rays const Point hitPoint = path->pathRay(rayHit.t); tracedShadowRayCount = 0; const float lightStrategyPdf = static_cast<float> (SHADOWRAY) / static_cast<float> (geometry->nLights); float lightPdf[SHADOWRAY]; RGB lightColor[SHADOWRAY]; Ray shadowRay[SHADOWRAY]; for (unsigned int i = 0; i < SHADOWRAY; ++i) { // Select the light to sample const unsigned int currentLightIndex = geometry->SampleLights(getFloatRNG(&path->seed)); // const TriangleLight &light = scene->lights[currentLightIndex]; // Select a point on the surface lightColor[tracedShadowRayCount] = Sample_L(currentLightIndex, geometry, hitPoint, shadeN, getFloatRNG(&path->seed), getFloatRNG(&path->seed), &lightPdf[tracedShadowRayCount], &shadowRay[tracedShadowRayCount]); // Scale light pdf for ONE_UNIFORM strategy lightPdf[tracedShadowRayCount] *= lightStrategyPdf; // Using 0.1 instead of 0.0 to cut down fireflies if (lightPdf[tracedShadowRayCount] > 0.1f) tracedShadowRayCount++; } RayHit* rh = new RayHit[tracedShadowRayCount]; for (unsigned int i = 0; i < tracedShadowRayCount; ++i) Intersect(shadowRay[i], rh[i], bvh->bvhTree, geometry->triangles, geometry->vertices); if ((tracedShadowRayCount > 0)) { for (unsigned int i = 0; i < tracedShadowRayCount; ++i) { const RayHit *shadowRayHit = &rh[i]; if (shadowRayHit->index == 0xffffffffu) { // Nothing was hit, light is visible path->radiance += path->throughput * lightColor[i] / lightPdf[i]; } } } //-------------------------------------------------------------------------- // Build the next vertex path ray //-------------------------------------------------------------------------- // Calculate exit direction float r1 = 2.f * M_PI * getFloatRNG(&path->seed); float r2 = getFloatRNG(&path->seed); float r2s = sqrt(r2); const Vector w(shadeN); Vector u; if (fabsf(shadeN.x) > .1f) { const Vector a(0.f, 1.f, 0.f); u = Cross(a, w); } else { const Vector a(1.f, 0.f, 0.f); u = Cross(a, w); } u = Normalize(u); Vector v = Cross(w, u); Vector newDir = u * (cosf(r1) * r2s) + v * (sinf(r1) * r2s) + w * sqrtf(1.f - r2); newDir = Normalize(newDir); path->pathRay.o = hitPoint; path->pathRay.d = newDir; return true; }